这个故事应该防止带有 AJAX 请求的 CSRF(跨站点请求原谅攻击)。
- 您可以放置一些标头数据并检查客户端是否请求它。
- 使用会话检查来自客户端的数据,并将其与服务器上的会话进行比较以访问 ajax 请求。
- 添加代码
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
以确保 xmlhttprequested 来自 ajax
- 如果您从服务器发送敏感数据并将其存储在有时间限制的客户端上,则生成一些令牌
令牌使用示例:
function checkToken( $userId, $eventIdentificator, $token){
if( $token == sha1( $some_value_grabbed_from_time )){
return true;
}
}
return false;
}
5. 添加时间限制用户以使用某些生成的密钥请求数据,以便将来不能在 GET 中使用此哈希密钥并防止对其进行攻击。
生成令牌示例:
protected static function _generateToken()
{
$token = sha1(mt_rand(0, 1000000));
$_SESSION[$token] = time();
return $token;
}
并将其验证为:
if ($_SESSION[$token] >= time() - 7200) {
$valid = true;
}
6. 您可以将 COOKIE 添加到 ajax 中,如 IT 安全性所示:https ://security.stackexchange.com/questions/20015/protecting-against-csrf-when-a-form-is-being-submitted-via-an- ajax 调用
7. 查看 Github 上的示例,如简单类所示:https ://github.com/foxbunny/CSRF4PHP
或者 ...
public function generateToken() {
// Create or overwrite the csrf entry in the seesion
$_SESSION['csrf'] = array();
$_SESSION['csrf']['time'] = time();
$_SESSION['csrf']['salt'] = $this->randomString(32);
$_SESSION['csrf']['sessid'] = session_id();
$_SESSION['csrf']['ip'] = $_SERVER['REMOTE_ADDR'];
// Generate the SHA1 hash
$hash = $this->calculateHash();
// Generate and return the token
return base64_encode($hash);
}
protected function checkTimeout($timeout=NULL) {
if (!$timeout) {
$timeout = $this->timeout;
}
return ($_SERVER['REQUEST_TIME'] - $_SESSION['csrf']['time']) < $timeout;
}
public function checkToken($timeout=NULL) {
// Default timeout is 300 seconds (5 minutes)
// First check if csrf information is present in the session
if (isset($_SESSION['csrf'])) {
// Check the timeliness of the request
if (!$this->checkTimeout($timeout)) {
return FALSE;
}
// Check if there is a session id
if (session_id()) {
// Check if response contains a usable csrf token
$isCsrfGet = isset($_GET['csrf']);
$isCsrfPost = isset($_POST['csrf']);
if (($this->acceptGet and $isCsrfGet) or $isCsrfPost) {
// Decode the received token hash
$tokenHash = base64_decode($_REQUEST['csrf']);
// Generate a new hash from the data we have
$generatedHash = $this->calculateHash();
// Compare and return the result
if ($tokenHash and $generatedHash) {
return $tokenHash == $generatedHash;
}
}
}
}
// In all other cases return FALSE
return FALSE;
}
}
此源代码显示为防止对侧 Ajax 请求进行 CSRF 攻击的最佳实践。它将检查从表单发送的生成数据的获取/发布,并与作为静态变量 ( _generateToken()
)放在 PHP 对象上的哈希值进行比较
8. OWASP
来自 Web 应用程序项目的展示展示了如何通过 X/CSRF 进行攻击的可用示例以及如何防止它们的可用示例。
链接:https ://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
大多数情况下,通常是原则上:“双重提交 cookie”,当脚本在每个请求上发送随机生成的 ID 并将其与先前发送的和新发送的 vars 进行比较时。
9. 编写您自己的 SCRIPT 以测试随机字符串攻击,使用 SHA512 进行更难的攻击,或仅使用下载进行测试:https ://www.owasp.org/index.php/Category:OWASP_CSRFTester_Project
10. 添加一些带有圆形示例 time() 的 HTTP HEADER 虚拟数据并比较示例是今天 ODD 或 EVEN 日或 ODD/EVEN 小时/分钟....
11. 如果在某个时间段(例如 3 分钟)内经常从一个 IP 地址受到攻击,则向管理员发出警报……或阻止临时远程主机……
12. 如果您仍然不知道 X/CSRF 的工作原理,请查看 YT 上的一些视频示例:http ://www.youtube.com/watch?v=pDXTDR6xew8
13. 如果您想知道如何使用crypt()
和一些 OLD SCHOOL CSRF 预防使用示例: http: //phpmaster.com/preventing-cross-site-request-forgeries/
或简单的代码:
session_start();
switch($_GET["action"]) {
case "login":
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$user = (isset($_POST["user"]) &&
ctype_alnum($_POST["user"]) ? $_POST["user"] : null;
$pass = (isset($_POST["pass"])) ? $_POST["pass"] : null;
$salt = '$2a$07$my.s3cr3t.SalTY.str1nG$';
if (isset($user, $pass) && (crypt($user . $pass, $salt) ==
crypt("admintest", $salt))) {
$_SESSION["user"] = $_POST["user"];
}
}
break;
case "logout":
$_SESSION = array();
session_destroy();
break;
}
header("Location: login.php");
14. 对于 CODEIGNITER/KOHANA 用户可以通过 HOOKS 简单地使用(在所有类之前作为类加载),并带有注入代码示例:http: //net.tutsplus.com/tutorials/php/protect-a-codeigniter-application-against -csrf/
防止通过 JAVASCRIPT 注入代码:
$output = preg_replace('/(<(form|FORM)[^>]*(method|METHOD)="(post|POST)"[^>]*>)/',
'$0<input type="hidden" name="' . self::$token_name . '" value="' . self::$token . '">', $output);
当您使用 JSON 数据发送或接收数据时进行 put SSL 数据传输,以防止嗅探或查看数据。
根据内容将哈希等数字签名放入标头中。例如,散列您的内容并放入头文件“Digital-Sign:md5-data”。内容应该被散列并作为数字签名的新变量放入标题中。客户端检查数据并使用哈希进行比较以进行检查是真的。您可以将盐与发送数据的时间戳结合使用。md5($timestasmp.$content)