程序员必须知道的十大网络安全风险

软件世界是建立在信任之上的:用户相信程序,程序相信数据,系统相信环境。 然而,只要存在输入、网络、用户与攻击者,这种信任就随时可能被打破。

下面总结了程序员必须了解的 十大网络安全风险。它们并不神秘,但都极其常见。一旦发生,会直接影响系统的可靠性、数据安全以及用户信任。

1. SQL 注入(SQL Injection)

SQL 注入是最经典也最基础的安全问题。 只要 SQL 是通过字符串拼接生成的,就可能被恶意修改逻辑。

示例:

query = f"SELECT * FROM users WHERE name = '{username}'"

username 为:

' OR 1=1 --

SQL 将变为:

SELECT * FROM users WHERE name = '' OR 1=1 --'

结果就是把整张表都查出来。

防御方式:

  • 使用参数化查询(Prepared Statement)
  • 永远不要用字符串拼接构造 SQL

2. 跨站脚本攻击(XSS)

XSS 的本质是:用户输入的内容被当作脚本执行了

例子:

<div>{{ nickname }}</div>

如果昵称是:

<script>alert('XSS')</script>

页面就会执行这段代码。

后果可能是窃取 Cookie、篡改页面、发起恶意请求等。

防御方式:

  • 输出前进行 HTML 转义
  • 使用默认防御 XSS 的模板引擎(React/Vue 等)

3. 跨站请求伪造(CSRF)

CSRF 的特点是:用户在登录状态下,被诱导访问某个恶意页面,然后浏览器自动携带 Cookie,导致后台执行了用户并未授权的操作。

例如:

<img src="https://bank.com/transfer?to=hacker&amount=5000">

只要用户登录过银行网站,这个请求就可能执行。

防御方式:

  • 使用 CSRF Token
  • 设置 Cookie 的 SameSite 属性
  • 对敏感操作要求二次确认

4. 弱密码与密码泄露

很多攻击并不依赖技术漏洞,而是依赖人类弱点。 弱密码(如 123456password)被暴力破解是十分常见的。

另一个问题是服务器端存储明文密码,一旦数据库泄露,就是灾难。

防御方式:

  • 要求使用复杂密码
  • 存储密码时使用强哈希算法(bcrypt / argon2)
  • 支持双因素认证(2FA)

5. 明文传输(HTTP)

HTTP 是明文的,任何中间节点都可以看到所有内容,包括账号密码。 在公共 WiFi 下尤为危险。

防御方式:

  • 全站使用 HTTPS
  • 不要将敏感数据暴露在 URL 查询参数中

6. 未授权访问(Broken Access Control)

这是后端最容易忽视的问题。 比如:

/admin/listUsers

如果后台只检查用户是否“已登录”,但不验证用户是否“管理员”,就会造成权限绕过。

防御方式:

  • 所有敏感接口都必须进行权限检查
  • 不要依赖前端控制权限

7. 文件上传漏洞

文件上传听起来很常见,但风险也极高。

例如:

  • 攻击者上传一张看起来是 .jpg 的文件,但实际上内部包含可执行代码
  • 上传目录允许执行脚本文件

一旦成功,攻击者可以直接控制服务器。

防御方式:

  • 校验文件的 MIME 类型而不是文件扩展名
  • 上传后重新命名文件
  • 将文件放在不可执行目录
  • 对图片进行重新编码以确保其内容安全

8. 暴露的管理接口

很多框架在开发模式下会暴露调试接口,例如:

/debug
/swagger-ui
/actuator

如果在生产环境中忘记关闭,就会造成极大的安全风险。

防御方式:

  • 生产环境关闭不必要的管理端口
  • 必须暴露的端点需要权限认证
  • 不在页面上输出敏感系统信息

9. 依赖与供应链攻击

现代开发高度依赖第三方库。 如果依赖包本身含有恶意代码(或被入侵),攻击者就能“曲线入侵”你的系统。

典型方式包括:

  • 伪装成相似名字的库
  • 在常见库中加入恶意更新
  • 泄露依赖版本导致漏洞被利用

防御方式:

  • 定期更新和扫描依赖
  • 锁定依赖版本
  • 只使用可信来源的包

10. 日志与调试信息泄露

日志里常出现敏感数据,例如:

Login failed: username=alice, password=secret

一旦日志泄露,相当于主动暴露系统内部状态。

数据泄露事件中,日志泄漏占比相当高。

防御方式:

  • 不记录密码、Token、身份证号等敏感数据
  • 控制日志访问权限
  • 在生产环境关闭过度详细的调试信息(如 stack trace)

总结

安全风险的根源往往不是复杂的攻击,而是我们理所当然的假设。

一个稳健的系统应该具备:

  1. 不信任任何输入
  2. 不依赖客户端安全
  3. 不暴露内部实现
  4. 对敏感数据尽量减少存储
  5. 始终假设攻击者存在

掌握这十大安全风险,可以帮助程序员在设计和构建系统时提前预判问题,减少代价高昂的“线上事故”。