Javascript 如何保护 Ajax 链接请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29842122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to secure Ajax link requests?
提问by Alpha2k
Imagine the next scenario: a user wants to register to a webpage and fills a form. While he is filling the form, jQuery keeps checking through a regular expressionif fields are valid, etc...
想象下一个场景:用户想要注册网页并填写表格。当他填写表单时,jQuery 会不断通过正则表达式检查字段是否有效等......
Taking the email as the primary key which the user will use after registering to login, the email field needs to be checked with Ajaxto let the user know if that email is registered or not. I want to check it with Ajax to avoid sending the full form and emptying it, refreshing page, etc...
将电子邮件作为用户注册登录后将使用的主键,需要使用Ajax检查电子邮件字段以让用户知道该电子邮件是否已注册。我想用 Ajax 检查它以避免发送完整的表单并将其清空、刷新页面等...
So, when the user has ended filling the email field, the Ajax request is sent to the server, something like the next link:
因此,当用户完成填写电子邮件字段时,Ajax 请求将发送到服务器,类似于下一个链接:
example.com/[email protected]
When check.php receives the email, it asks the database if it exists or not and returns a message like: User already existsif user exists or nullif user does not exist.
当 check.php 收到电子邮件时,它会询问数据库是否存在并返回一条消息,例如:User already exists如果用户存在或null用户不存在。
The question is:if someone digs through my .js and finds out links similar to that, they could use that link to send a large number of requests to find out if those random emails exist. This could lead to heavy use of the database or in the worst cases even crashing and private information leaks.
问题是:如果有人在我的 .js 中挖掘并找到类似的链接,他们可以使用该链接发送大量请求,以确定这些随机电子邮件是否存在。这可能导致数据库的大量使用,或者在最坏的情况下甚至崩溃和私人信息泄漏。
Someone could do a huge for loop to check emails like:
有人可以做一个巨大的 for 循环来检查电子邮件,例如:
//Getting the response of the next links
example.com/[email protected] // Returns null
example.com/[email protected] // Returns null
example.com/[email protected] // Returns null
example.com/[email protected] // Returns User already exists
------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------- -------------------------------------------------- --------------------------------
Since i last accepted the answer, i kept investigating this and found the solution to avoid this behaviour. The following code is for JAVA but the logic can be applied to any other server-side language.
自从我上次接受答案以来,我一直在对此进行调查,并找到了避免这种行为的解决方案。以下代码适用于 JAVA,但该逻辑可以应用于任何其他服务器端语言。
Before doing ANY ajax request to the server, I request a token to the server. This token looks like this fmf5p81m6e56n4va3nkfu2ns8nit is made by a simple method, it can, however, be more complex, but this is good to go.
在向服务器发出任何 ajax 请求之前,我向服务器请求一个令牌。这个令牌看起来像这样,fmf5p81m6e56n4va3nkfu2ns8n它是由一种简单的方法制成的,但是它可以更复杂,但这很好。
public String getToken() throws UnsupportedEncodingException {
return new BigInteger(130, new SecureRandom()).toString(32);
}
When requesting the token, the server does not only return the token, but also a small script that in case someone uses browser to inspect element (and browser navbar) and such the script will run and the token will be cleared. Servlet returns something like this:
当请求令牌时,服务器不仅会返回令牌,还会返回一个小脚本,以防有人使用浏览器检查元素(和浏览器导航栏),这样脚本将运行并清除令牌。Servlet 返回如下内容:
_html += "<head>"
+ "<script> "
+ "window.onload=function(){\n"
+ " document.body.innerHTML = \"\";\n"
+ " }"
+ "window.location.href='http://mywebsite.com' "
+ "</script>"
+ "</head>"
+ "<body>"
+ "[" + token+ "]"
+ "</body>"
+ "</html>";
First empties the body then navigates back to wherever we want. javascript/jquery will however, catch the entire content as string, then I simply extract the string between [ and ]. This token is only available for the next request, so every AJAX request will have its unique token. On the 2nd reques the token just used is deleted.
首先清空主体然后导航回我们想要的任何地方。但是,javascript/jquery 会将整个内容捕获为字符串,然后我只需提取 [ 和 ] 之间的字符串。此令牌仅可用于下一个请求,因此每个 AJAX 请求都有其唯一的令牌。在第二次请求时,刚刚使用的令牌被删除。
After I get the token I append it as parameter to whatever link i request, something like this:
获得令牌后,我将其作为参数附加到我请求的任何链接中,如下所示:
ajaxRequestObjet = $.ajax({
url: "http://localhost:8084/mywebsite.com/servlet", //<-- local tomcat server
method: "POST",
data: "type=AJAX&page=some-article&token=fmf5p81m6e56n4va3nkfu2ns8n"
});
This method works fine against someone who inspects the website manually and try to use the links, but what about java/php/IIS servers that do this automaticly?
这种方法对于手动检查网站并尝试使用链接的人来说效果很好,但是自动执行此操作的 java/php/IIS 服务器呢?
For this ask for header! Something like this:
为此要求标题!像这样的东西:
boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
It will be true only and only if XMLHttpRequest exists....
仅当 XMLHttpRequest 存在时才会为真....
There is one last thing to keep in mind. Make sure 'Access-Control-Allow-Origin' header is NOT present in your appto make sure that any javascript NOT in your server wont get the server resources. If this header does not exist, chrome will return this:
最后一件事要记住。确保确保'Access-Control-Allow-Origin' header is NOT present in your app不在您的服务器中的任何 javascript 都不会获取服务器资源。如果此标头不存在,chrome 将返回:
XMLHttpRequest cannot load http://localhost:8084/mywebsite.com/servlet. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Java server was in tomcat and I had another apache for this tests, this is the small html present in apache which gave the error above:
Java 服务器在 tomcat 中,我有另一个 apache 用于此测试,这是 apache 中存在的小 html,它给出了上述错误:
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script>
ajaxRequestObjet = $.ajax({
url: "http://localhost:8084/mywebsite.com/servlet",
method: "POST",
data: "type=AJAX&page=Token"
});
ajaxRequestObjet.done(function (msg) {
alert(msg);
});
</script>
</head>
<body>
</body>
</html>
采纳答案by Angry 84
While you can not control this 100%... there are a few options..
虽然你不能 100% 控制这个......有几个选项......
Try using the same methods that people use with Captcha scripts..
尝试使用人们在 Captcha 脚本中使用的相同方法。
Basically when the user loads the form / page.. You generate a random string/id in their PHP session and store it.. When they send the ajax requests, have your ajax check also append the string/id and require it before allowing a check to perform else return a header of 500 or something..
基本上当用户加载表单/页面时.. 你在他们的 PHP 会话中生成一个随机字符串/id 并存储它.. 当他们发送 ajax 请求时,让你的 ajax 检查也附加字符串/id 并在允许之前要求它检查以执行其他返回 500 或其他内容的标头..
Using this approach with sessions, you could set a allowed limit of checks (say 5) and once the user has tried more than 5 checks, They are required to reload the page or perform a human check (eg Captcha).. Then it resets their count.. Even allow a total of say 30 within 1 hour / per IP or something.
将这种方法与会话一起使用,您可以设置允许的检查限制(例如 5 个),一旦用户尝试了 5 个以上的检查,他们就需要重新加载页面或执行人工检查(例如验证码)。然后它会重置他们的数量..甚至允许在 1 小时内/每个 IP 或其他东西总共说 30 个。
Also use smart events to trigger when the ajax check is done, eg field/tab change or on a button press.. Or when a valid email is detected.. but say .com.au would trigger twice.
还可以使用智能事件在 ajax 检查完成时触发,例如字段/选项卡更改或按下按钮时.. 或者当检测到有效电子邮件时.. 但说 .com.au 会触发两次。
Basically this way, even if someone sniffed your JS files and tried to automate the email checker.. It would require them finding a way to append the string/id that you generate and also limit their amount of requests performed.
基本上这样,即使有人嗅探了您的 JS 文件并尝试自动执行电子邮件检查器.. 这将要求他们找到一种方法来附加您生成的字符串/ID,并限制他们执行的请求数量。
Beyond this, there is not to much more you can do easily.. But there are still a few other idea's.
除此之外,您可以轻松完成的事情不多了。但仍有一些其他想法。
Most of them would work around using a PHP session / cookie.. Say for example if they check and find 3 email addresses.. Then again you set that as a limit and force them to require a manual submission or something.
他们中的大多数人会使用 PHP 会话/cookie 来解决.. 例如,如果他们检查并找到 3 个电子邮件地址.. 然后您再次将其设置为限制并强制他们要求手动提交或其他内容。
See how the above suggestion goes for you, any questions do feel free to ask. But may take me a day or two to reply as weekend.. Also research how Captcha scripts work as plenty of source code for them.. As they work on the same idea.
看看上面的建议对你有什么影响,任何问题都可以随时提出。但可能需要我一两天的时间来回复作为周末.. 还要研究验证码脚本如何作为大量源代码为他们工作.. 因为他们在同一个想法上工作。
Time Delayswill simply look bad / make your site appear slow / bug the user with waiting for a response.
时间延迟只会看起来很糟糕/让您的网站看起来很慢/让用户等待响应。
You need to limit the amount of look up's per session / ip address.. Otherwise there is always a way to get past these checks.. Basically once they hit a limit.. Force the user/ip/session to wait a few minutes/hours and verify them with a Captcha script so it can not be scripted...
您需要限制每个会话/IP 地址的查找量.. 否则总有办法通过这些检查.. 基本上一旦达到限制.. 强制用户/IP/会话等待几分钟/小时并使用 Captcha 脚本验证它们,因此无法编写脚本...
Javascript Security / Hiding The Source
Javascript 安全性/隐藏源代码
While you can not do this truly, you can do certain things generate the JS using a PHP page with a JS header.. so <script src='myjscode.php'></script>and this allows PHP to check for a valid session.. So stops external requests to an extent.. But this is mostly useful for allowing JS to be only available behind a membership/login..
虽然您不能真正做到这一点,但您可以使用带有 JS 标头的 PHP 页面来执行某些操作来生成 JS .. 所以<script src='myjscode.php'></script>这允许 PHP 检查有效会话.. 所以在一定程度上停止外部请求.. 但这主要用于允许 JS 仅在会员/登录后可用。
Multiple Checks / If Possible In This Case
多次检查/如果可能在这种情况下
Depending on your approach, is this for a user to check if they already have an account? If so.. you could combine the email check with something like their name/country/age/dob ... So they would need to select two or three correct matching values before being able to get a check/response from the ajax call?
根据您的方法,这是让用户检查他们是否已经拥有帐户吗?如果是这样......你可以将电子邮件检查与他们的姓名/国家/年龄/dob 结合起来......所以他们需要选择两个或三个正确的匹配值才能从ajax调用中获得检查/响应?
Maybe not in your case, but just thought would add this as well.
也许不是你的情况,但只是想也会添加这个。
回答by Johannes Reuter
The JavaScript code on your website is executed on the computer of the user, so there is no way you could stop him from digging through your code. Even if you use a code obfuscator (for example, https://www.javascriptobfuscator.com/), the hacker could debug your application and record all requests send to the server.
您网站上的 JavaScript 代码在用户的计算机上执行,因此您无法阻止他挖掘您的代码。即使您使用代码混淆器(例如https://www.javascriptobfuscator.com/),黑客也可以调试您的应用程序并记录发送到服务器的所有请求。
Everything security-relevant has to happen on the server. You could limit the amount of requests from a specific IP address.
所有与安全相关的事情都必须在服务器上发生。您可以限制来自特定 IP 地址的请求数量。
回答by joews
You could protect against brute force attacks with something similar to CSRF tokens:
您可以使用类似于CSRF 令牌的东西来防止暴力攻击:
Assign a server-generated ID to every client session. Each request to check.phpshould include this ID.
为每个客户端会话分配一个服务器生成的 ID。每个请求check.php都应包含此 ID。
check.phpshould reject requests that do not include an ID, or include an ID that the server did not generate (to prevent attacks with spoofed IDs). It should also rate limit on ID - if a given ID has made a request in (say) the last second, or a given ID makes more than nrequests in a 10 second interval, it should return an error response. This protects against requests from a single session arriving from several IP addresses.
check.php应拒绝不包含 ID 或包含服务器未生成的 ID 的请求(以防止使用欺骗 ID 进行攻击)。它还应该对 ID 进行速率限制 - 如果给定的 ID 在(比如)最后一秒发出了请求,或者给定的 IDn在 10 秒的间隔内发出的请求超过请求,则它应该返回错误响应。这可以防止来自多个 IP 地址的单个会话的请求。
You should also rate limit by IP address to prevent brute-forcing by opening a large number of web application sessions.
您还应该通过 IP 地址进行速率限制,以防止通过打开大量 Web 应用程序会话来进行暴力破解。
There isn't much you can do to prevent an attacker looking up a single, or small number, of specific email addresses - it's an inherent risk with this type of validation.
您无能为力阻止攻击者查找单个或少量特定电子邮件地址 - 这是此类验证的固有风险。
回答by MrCode
This type of attack can be treated the same as any other brute force attack, where the only effective solution is to use a Captcha. But of course, Captchas are a detriment to UX, so you have to consider if the additional security is worth it, especially for an attack that is very unlikely to happen anyway. That said, you may want to use a Captcha on your registration form anyway, to prevent bots from creating accounts.
这种类型的攻击可以与任何其他蛮力攻击一样对待,其中唯一有效的解决方案是使用Captcha。但当然,验证码对用户体验有害,因此您必须考虑额外的安全性是否值得,尤其是对于无论如何都不太可能发生的攻击。也就是说,您可能希望在注册表单上使用验证码,以防止机器人创建帐户。
This sort of attack has a huge cost for little reward for the attacker. There are billions of possible email addresses to test for. It could only be worth going to great lengths such as this, if the site in question was particularly sensitive, such as some kind of adult site, where the attacker hopes to blackmail users that he finds.
这种攻击付出了巨大的代价,而攻击者的回报却很少。有数十亿个可能的电子邮件地址需要测试。如果所讨论的站点特别敏感,例如某种成人站点,攻击者希望在其中勒索他发现的用户,那么像这样进行大量工作是值得的。
CloudFlare
云耀斑
Not as good as a Captcha solution but the brute force attack might be detected and prevented by CloudFlare's DDoSsystem. Also, CF can force Tor users to solve a Captcha before accessing your site, which would prevent an attacker from using Tor as a vehicle for the attack.
不如 Captcha 解决方案好,但 CloudFlare 的DDoS系统可能会检测到并阻止蛮力攻击。此外,CF 可以强制 Tor 用户在访问您的站点之前解决验证码,这将防止攻击者使用 Tor 作为攻击工具。
IP Rate Limiting
IP 限速
Rate limiting on an IP basis has problems because if an attacker decided to undertake a task as huge as this, he will likely be using a Botnetor some other system of multiple machines to launch the attack.
基于 IP 的速率限制存在问题,因为如果攻击者决定承担如此庞大的任务,他很可能会使用僵尸网络或其他多台机器系统来发起攻击。
Consider a large organisation such as a University, where all users share the public IP. One of the users launches an attack on your site, and you block his IP, and in the processes blocking everyone else. This countermeasure could actually be used to launch a DoSattack.
考虑一个大型组织,例如大学,所有用户都共享公共 IP。其中一位用户对您的站点发起攻击,您阻止了他的 IP,并在此过程中阻止了其他所有人。这种对策实际上可以用来发起DoS攻击。
Session ID/CRSF Token
会话 ID/CRSF 令牌
Definitely not a solution because the attacker needs to simply make a request to the page first, to obtain the token. It's an additional request to make but only an inconvenience for the attacker.
绝对不是解决方案,因为攻击者只需要先向页面发出请求即可获取令牌。这是一个额外的请求,但只会给攻击者带来不便。
回答by Stephan Weinhold
First of all: I'd URL-encode the mail-address. 'example.com/check.php?email=' . urlencode([email protected])
首先:我会对邮件地址进行 URL 编码。 'example.com/check.php?email=' . urlencode([email protected])
Ad your question: when check.php is called, you can
广告您的问题:调用 check.php 时,您可以
- check, if the user's session and his IP have sent a request during the last seconds
- if not, write the user's session, the user's IP plus the current timestamp to a helper-table plus to a cookie and hit your DB
- if yes, block the request
- 检查用户的会话和他的 IP 在最后几秒内是否发送了请求
- 如果没有,将用户的会话、用户的 IP 加上当前时间戳写入帮助表加上 cookie 并点击您的数据库
- 如果是,则阻止请求
But I'm afraid this won't help you from fraud because everyone can check your JavaScript and if someone want's to exploit this, he will find ways.
但是我担心这不会帮助你避免欺诈,因为每个人都可以检查你的 JavaScript,如果有人想利用它,他会想办法。
回答by Nick Sterckx
check.php should depending on the setup either only be accessible internally, or verify from where the connection is made. Take a look at this previous question- I hope it might be what you're looking for. how to verify the requesting server in php?
check.php 应该取决于设置,或者只能在内部访问,或者验证从哪里建立连接。看看这个以前的问题 - 我希望它可能是你正在寻找的。如何在php中验证请求服务器?
回答by Cristik
You could use a CSRF tokenand exit early from your script if you detect that no or an invalid CSRF token. Almost (if not all) PHP frameworks come with support for this.
CSRF token如果您检测到 no 或无效 ,则可以使用 a并尽早退出脚本CSRF token。几乎(如果不是全部)PHP 框架都支持这一点。
Also check this question from the security community: https://security.stackexchange.com/questions/23371/csrf-protection-with-custom-headers-and-without-validating-token
还要从安全社区检查这个问题:https: //security.stackexchange.com/questions/23371/csrf-protection-with-custom-headers-and-without-validating-token
回答by Anuj Taya Ror
One approach to resolve this problem could be this:
解决此问题的一种方法可能是:
Suppose you have ajax request calling your server to receive a response from a particular user or client. You can have a table in your database where you provide a unique token for every user or hash value that can be checked every time user makes an ajax request to the server. If the token value matches the user request value than he is a genuine user. You can also record his number of request on the table to ensure he is making legitimate requests. I acknowledge the fact that it may slow down your app performance, but it will be safe option to consider. Note: you need to retrieve the token on your HTML page to send it with ajax.
假设您有 ajax 请求调用您的服务器以接收来自特定用户或客户端的响应。您可以在数据库中有一个表,您可以在其中为每个用户或哈希值提供一个唯一的令牌,每次用户向服务器发出 ajax 请求时都可以检查该令牌。如果令牌值与用户请求值匹配,则他是真正的用户。您还可以在表上记录他的请求数量,以确保他提出的请求是合法的。我承认它可能会降低您的应用程序性能,但这是一个安全的选择。注意:您需要在 HTML 页面上检索令牌以使用 ajax 发送它。
Please comment to know more. I have been using this approach and there is no problem until now.
请发表评论以了解更多信息。我一直在使用这种方法,直到现在都没有问题。
Example:
例子:



