如何保护 AJAX 或 javascript Web 应用程序
Posted
技术标签:
【中文标题】如何保护 AJAX 或 javascript Web 应用程序【英文标题】:How to protect AJAX or javascript web application 【发布时间】:2020-07-03 07:56:58 【问题描述】:这是一个简单的函数,它使用 AJAX 并在单击按钮时获取数据库中 id=219 的图像信息
任何加载此网页的人都可以通过转到源代码来更改 javascript 代码。 然后通过单击按钮,他将运行修改后的代码(例如将 image_id 从 219 更改为 300)。所以他可以通过改变 image_id 来获取任何图像的信息
问题是如何防范客户端攻击或 XSS?
function clicked ()
var xhttp = new XMLHttpRequest () ;
xhttp.onreadystatechange = function ()
if (this.readyState == 4 && this.status == 200)
var obj = JSON.parse (this.responseText);
alert (obj.description);
;
xhttp.open ("POST","get_title_description.php", true);
xhttp.setRequestHeader ("Content-type", "application/x-www-form-urlencoded");
xhttp.send ("image_id=219") ;
【问题讨论】:
黄金法则是.. 永远不要相信客户。在服务器端进行安全/验证/身份验证 前端和后端都必须进行验证,因为有人可能会使用邮递员之类的东西绕过前端验证,因此服务器必须验证它收到的内容。这是必须的 我使用 PHP 作为后端语言。你能发布一个关于如何在后端防止这种情况的例子吗?也许一种方法是检查会话 id 是否等于该图像表中的 user_id ? (以确保他不能查看其他用户的图像) 您应该只允许在客户端提供 cookie 的情况下获取图像 - 并且此 cookie 必须具有HttpOnly
标志并使用一种对称加密算法(例如 AES-256)进行加密。 cookie 的有效期必须很短 - 例如10-15 分钟
@IVOGELOV 该 cookie 的值应该是多少?并且基于什么应该允许用户获取图像?
【参考方案1】:
您可以使用类似的东西来生成和验证 cookie:
define('COOKIE_TOKEN', 'my_token');
class BaseAuth
protected $uid;
private static function base64url_encode(string $s): string
return strtr($s,'+/=','-|_');
private static function base64url_decode(string $s): string
return strtr($s,'-|_','+/=');
// Encodes after encryption to ensure encrypted characters are URL-safe
protected function token_encode(String $string): string
$iv_size = openssl_cipher_iv_length(TYPE_CRYPT);
$iv = openssl_random_pseudo_bytes($iv_size);
$encrypted_string = @openssl_encrypt($string, TYPE_CRYPT, SALT, 0, $iv);
// Return initialization vector + encrypted string
// We'll need the $iv when decoding.
return self::base64url_encode($encrypted_string).'!'.self::base64url_encode(base64_encode($iv));
// Decodes from URL-safe before decryption
protected function token_decode(String $string): string
// Extract the initialization vector from the encrypted string.
list($encrypted_string, $iv) = explode('!', $string);
$string = @openssl_decrypt(self::base64url_decode($encrypted_string), TYPE_CRYPT, SALT, 0, base64_decode(self::base64url_decode($iv)));
return $string;
// performs log-out
public function clear_cookie()
setcookie(COOKIE_TOKEN, '', time() - 300, '/api', '', FALSE, TRUE); // non-secure; HTTP-only
private function userIP(): string
return $_SERVER['REMOTE_ADDR'];
// validates Login token
public function authorized(): bool
if(isset($_COOKIE[COOKIE_TOKEN]))
$stamp = time();
$text = $this->token_decode($_COOKIE[COOKIE_TOKEN]);
if($text != '')
$json = json_decode($text,TRUE);
if(json_last_error() == JSON_ERROR_NONE)
if($json['at'] <= $stamp AND $json['exp'] > $stamp AND $json['ip'] == $this->userIP() AND $json['id'] != 0)
// check if user account is still active
$res = $db->query("SELECT id,active,last_update,last_update > '".$json['last']."'::timestamptz AS expired FROM account WHERE id = ".$json['id']);
$info = $db->fetch_assoc($res);
if($info['active'] != 0)
if($info['expired'] == 0)
// extend the token lifetime
$this->sendToken($info);
$this->uid = $json['id'];
return TRUE;
$this->clear_cookie();
return FALSE;
public function login(String $username, String $password): bool
$stm = $db-prepare("SELECT id,user_name AS username,user_pass,full_name,active,last_update,COALESCE(blocked_until,NOW()) > NOW() AS blocked
FROM account WHERE user_name = :user");
$res = $stm->execute(array('user' => strtolower($json['username'])));
if($res->rowCount())
$info = $db->fetch_assoc($res);
if($info['active'] == 0)
// Account is disabled
return FALSE;
elseif($info['blocked'] != 0)
// Blocked for 5 minutes - too many wrong passwords
// extend the blocking
$db->query("UPDATE account SET blocked_until = NOW() + INTERVAL 5 minute WHERE id = ".$info['id']);
return FALSE;
elseif(!password_verify($password, $info['user_pass']))
// Wrong password OR username
// block account
$db->query("UPDATE account SET blocked_until = NOW() + INTERVAL 5 minute WHERE id = ".$info['id']);
return FALSE;
else
unset($info['user_pass']);
unset($info['blocked']);
$this->sendToken($info);
return TRUE;
如果您不需要对用户进行身份验证和授权,而只需要随机的不可预测的图像 ID - 您可以简单地使用 UUID。
【讨论】:
以上是关于如何保护 AJAX 或 javascript Web 应用程序的主要内容,如果未能解决你的问题,请参考以下文章
从javascript传递到web api 2时如何隐藏或保护令牌
如何从 Ajax 或 JavaScript 调用 Struts1 Action?