CSRF defense can start from both the server side and the client side. The defense effect is better if it starts from the server side. Nowadays, general CSRF defense is also carried out on the server side.
1. CSRF defense on the server side
There are many ways to implement CSRF on the server side, but the general idea is the same, which is to add pseudo-random numbers to the client page.
(1).Cookie Hashing (all forms contain the same pseudo-random value):
This may be the simplest solution, because the attacker cannot obtain third-party cookies (theoretically), so the The data construction failed:>
<?php //构造加密的Cookie信息 $value = “DefenseSCRF”; setcookie(”cookie”, $value, time()+3600); ?>
Add a Hash value to the form to verify that this is indeed a request sent by the user.
<?php $hash = md5($_COOKIE['cookie']); ?> <form method=”POST” action=”transfer.php”> <input type=”text” name=”toBankId”> <input type=”text” name=”money”> <input type=”hidden” name=”hash” value=”<?=$hash;?>”> <input type=”submit” name=”submit” value=”Submit”> </form>
Then perform Hash value verification on the server side
<?php if(isset($_POST['check'])) { $hash = md5($_COOKIE['cookie']); if($_POST['check'] == $hash) { doJob(); } else { //... } } else { //... } ?>
Personally, I think this method can eliminate 99% of CSRF attacks, but there is still 1%... Because the user's cookies are easily compromised due to the XSS vulnerability of the website. Stolen, that's another 1%. Most attackers will basically give up when they see the need to calculate hash values, except for some, so if you need to eliminate it 100%, this is not the best method.
(2).Verification code
The idea of this solution is: every time the user submits, the user needs to fill in a random string on the picture in the form, eh... This solution can completely solve CSRF, but personally I feel that the ease of use is not very good, and I heard that the use of verification code images involves a bug called MHTML, which may be affected in some versions of Microsoft IE.
(3).One-Time Tokens (different forms contain a different pseudo-random value)
When implementing One-Time Tokens, you need to pay attention to one thing: "parallel session compatibility". If a user opens two different forms on a site at the same time, CSRF protection measures should not affect his submission of any form. Consider what would happen if the site generated a pseudo-random value every time a form was loaded, overwriting the previous pseudo-random value: the user could only successfully submit the form he last opened, because all other forms would contain illegal Pseudorandom value. Care must be taken to ensure that CSRF protection does not affect tabbed browsing or the use of multiple browser windows to browse a site.
The following is my implementation:
1). First the token generation function (gen_token()):
<?php function gen_token() { //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。 //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》 $token = md5(uniqid(rand(), true)); return $token; }
2). Then the Session token generation function (gen_stoken()):
<?php function gen_stoken() { $pToken = ""; if($_SESSION[STOKEN_NAME] == $pToken){ //没有值,赋新值 $_SESSION[STOKEN_NAME] = gen_token(); } else{ //继续使用旧的值 } } ?>
3). WEB form Function to generate hidden input fields:
<?php function gen_input() { gen_stoken(); echo “<input type=\”hidden\” name=\”" . FTOKEN_NAME . “\” value=\”" . $_SESSION[STOKEN_NAME] . “\”> “; } ?>
4). WEB form structure:
<?php session_start(); include(”functions.php”); ?> <form method=”POST” action=”transfer.php”> <input type=”text” name=”toBankId”> <input type=”text” name=”money”> <? gen_input(); ?> <input type=”submit” name=”submit” value=”Submit”> </FORM>
5). Server-side verification token:
This is very simple, so I won’t go into details here.
In fact, the above does not fully comply with the "parallel session compatibility" rules. You can modify it on this basis.