仅检查 Referer header 是否足以防止 CSRF?

Is just checking the Referer header enough to prevent CSRF?

正在比较 Referer http header 足以防止 CSRF,我在下面有以下 html 代码。

<div id="Message"></div><br>
Username:<br>
<input type="text" name="Username" id="Username"><br>
Password:<br>
<input type="password" name="Password" id="Password"><br>
Keep me logged in:<br>
<input type="checkbox" id="KeepSessionAlive"><br>
<input type="submit" onClick="ProcessLogin();">
<script>
function ProcessLogin(){
    Username=document.getElementById("Username").value;
    Password=document.getElementById("Password").value;
    KeepSessionAlive=document.getElementById("KeepSessionAlive").value;
    var xmlhttp;
    if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp=new XMLHttpRequest();
    }else{// code for IE6, IE5
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange=function(){
            if (xmlhttp.readyState==4 && xmlhttp.status==200){
                    document.getElementById("Message").innerHTML=xmlhttp.responseText;
            }
    }
    xmlhttp.open("POST","/Login/Process",true);
    xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xmlhttp.send("<A>Username</A><B>"+Username+"</B><A>Password</A><B>"+Password+"</B><A>KeepSessionAlive</A><B>"+KeepSessionAlive+"</B>");
}
</script>

这只是一个标准的 html 形式,但我想知道如果我使用下面的代码,我是否可以完全免受 CSRF 攻击。

class LoginProcess(webapp2.RequestHandler):
    def post(self):
        self.response.headers['Content-Type'] = 'text/plain'
        HTTTP_REFERER=self.request.referer
        if HTTP_REFER=="http://example.com":
            self.response.write('Referer: '+cgi.escape(HTTTP_REFERER))

是的,这足够了,但它被认为是一种较弱的保护形式:

Although it is trivial to spoof the referer header on your own browser, it is impossible to do so in a CSRF attack. Checking the referer is a commonly used method of preventing CSRF on embedded network devices because it does not require a per-user state. This makes a referer a useful method of CSRF prevention when memory is scarce. This method of CSRF mitigation is also commonly used with unauthenticated requests, such as requests made prior to establishing a session state which is required to keep track of a synchronization token.

However, checking the referer is considered to be a weaker from of CSRF protection. For example, open redirect vulnerabilities can be used to exploit GET-based requests that are protected with a referer check and some organizations or browser tools remove referrer headers as a form of data protection. There are also common implementation mistakes with referer checks. For example if the CSRF attack originates from an HTTPS domain then the referer will be omitted. In this case the lack of a referer should be considered to be an attack when the request is performing a state change. Also note that the attacker has limited influence over the referer. For example, if the victim's domain is "site.com" then an attacker have the CSRF exploit originate from "site.com.attacker.com" which may fool a broken referer check implementation. XSS can be used to bypass a referer check.

In short, referer checking is a reasonable form of CSRF intrusion detection and prevention even though it is not a complete protection. Referer checking can detect some attacks but not stop all attacks. For example, if you HTTP referrer is from a different domain and you are expecting requests from your domain only, you can safely block that request.

如果你想要 "quick method" 防止 CSRF 来自 XHR,你可以设置并检查自定义 header 例如 X-Requested-With. This is presently secure, however the recommended approach is the Synchronizer Token Pattern. This is more robust against flaws in browser plugins, such as an old vulnerability in Flash 允许设置 headers通常不应该。