如何阻止外部HTTP请求?(保护AJAX调用)

7
我想使用POST方法更新数据库,不希望用户手动操作,即只能通过客户端的AJAX进行。在这种情况下,是否有一些众所周知的密码学技巧可供使用?
比如,我向site.com/adduser/<userid>发送GET请求以将新用户插入到我的数据库中。但是,有人可能会通过发出虚假请求来过度填充我的数据库。

请澄清您的问题。 - Sameh Serag
7
除了数据检索之外,不应将GET用于任何其他目的。 - Gumbo
使用GET更容易,例如,我可能仍然会使用POST。 - Peteris
2
遗憾的是,加密并不是一根魔杖,你可以挥舞它使任何东西只做你想要的事情。有些人花费数十亿美元来弄清楚这一点(整个数字版权管理行业都在非常努力地解决这个问题)。不要成为那些人。 - Enno
可能是防止ajax函数调用的文件被直接访问的重复问题。 - IMSoP
8个回答

7

在这种情况下,无法避免伪造请求,因为客户端浏览器已经拥有了发出请求所需的一切;对于恶意用户来说,只需要进行一些调试就可以弄清楚如何向后端发出任意请求,甚至可能使用您自己的代码让它变得更容易。你不需要"加密技巧",你只需要混淆,这只会使伪造变得有些麻烦,但仍然不是不可能的。


我担心会出现这种情况。如果有人有任何混淆技巧建议,我全听着呢。 - Peteris

4
可以实现。每次呈现一个需要进行此类请求的页面时,请生成一个随机令牌并将其存储在会话(对于经过身份验证的用户)或数据库(在公开允许此类请求的情况下)中。而不是调用site.com/adduser/<userid>,请调用site.com/adduser/<userid>/<token>。每当您接收到这样的请求时,请检查令牌是否有效(从会话或数据库中),如果正确,则处理请求并从会话/数据库中删除已使用的令牌;如果不正确,则拒绝请求。请注意保留HTML标记。

3
我并不需要限制服务器访问(虽然这会很好),我正在寻找一种加密技巧,使服务器知道事物来源于应用程序而不是由用户使用嗅探令牌伪造的。但无法做到这一点。这几乎是客户端/服务器应用程序的基本问题之一。这里是为什么它行不通:假设您有一种方法让客户端应用程序向服务器进行身份验证-无论是秘密密码还是其他方法。应用程序所需的信息必须可访问(密码或其他信息隐藏在其中),但因为它运行在用户的计算机上,这意味着他们也可以访问此信息:他们只需查看源代码、二进制文件或应用程序与服务器之间的网络流量,最终他们将找出您的应用程序进行身份验证的机制,并复制它。也许他们甚至会复制它。也许他们会编写一个巧妙的黑客来让您的应用程序承担繁重的工作(您始终可以向应用程序发送虚假用户输入)。但无论如何,他们已经获得了所有必要的信息,没有办法阻止他们拥有这些信息,而不会也阻止您的应用程序拥有这些信息。

1
这是我见过的关于各种重复问题的最好解释。你应该将它添加到https://dev59.com/9nI-5IYBdhLWcg3woJ5J,这是这个问题的最古老的重复。 - IMSoP
你说得对,@IMSoP,在那个帖子的回答中确实有很多无能之辈。我稍微修改了我的回复,因为OP真正需要的是指向认证方向的指引。 - Enno

1

防止通过ajax函数调用的文件直接访问似乎解决了这个问题。

您可以(当然还有其他解决方案)...

  • 使用会话管理(登录以创建会话);
  • 向客户端发送一个唯一的密钥,在过期之前需要返回它(不能被重复使用,也不能被存储以供以后使用);
  • 和/或设置如链接答案中所述的标头。

但是,如果人们足够努力,任何东西都可以被欺骗。唯一完全安全的系统是根本无法访问的系统。


1
这与CSRF问题相同 - 解决方案也是相同的:在AJAX请求中使用一个令牌,该令牌先前已存储在其他地方(或可以重新生成,例如通过使用会话ID作为密钥加密参数)。Chriss Shiflett对此有一些明智的注释,而OWASP项目则用于检测PHP中的CSRF。

1
这不完全是CSRF问题。在CSRF中,这是一个身份问题,但我担心用户自己可能会滥用他们自己的登录凭据、自己的会话令牌,并使用自己的帐户来人为地填充数据库。 - Peteris
鉴于无法将服务器访问限制为仅限您的ajax API,这与CSRF完全相同。 - symcbean
我并不真正需要限制对服务器的访问(虽然那样会很好),我正在寻找一种加密技巧,使得服务器能够知道某些东西来自应用程序而非被用户伪造的嗅探令牌。 - Peteris
为什么不使用仅在短时间内有效的令牌?(但足以完成您的AJAX请求)。您可以基于服务器时间使用秘密算法生成代码,该算法在客户端和服务器中均已实现。客户端将向其请求添加此代码,服务器将检查代码是否仍然有效。类似于IPsec的“技巧”,以避免重放攻击。如果数字无效,则请求将被丢弃。请注意,这只是一个想法,我没有可用的工作代码! - StepTNT

0
解决方案是在ajax请求中添加粗体行。此外,您应该查看基本身份验证,这不会是唯一的保护程序。您可以使用以下代码从ajax页面捕获收入。
Ajax调用
function callit()
{
 if(window.XMLHttpRequest){xmlhttp=new XMLHttpRequest();}else{xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
 xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState==4&&xmlhttp.status==200){document.getElementById('alp').innerHTML=xmlhttp.responseText;}}
 xmlhttp.open("get", "call.asp", true);
 **xmlhttp.setRequestHeader("X-Requested-With","XMLHttpRequest");**
 xmlhttp.send();
}

PHP/ASP 请求页面响应

ASP

If Request.ServerVariables("HTTP_X-Requested-With") = "XMLHttpRequest" Then
 'Do stuff
Else
 'Kill it
End If

PHP

if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) )
{
 //Do stuff
} else {
 //Kill it
}

1
感谢您的努力,但正如其他人所提到的那样,这只是一个标题检查。这种方法并不安全,因为用户可以伪造标题。 - Peteris

0

它的工作方式与其他网页相同:登录验证,检查引荐者。


你能澄清一下吗?你是说服务器应用程序将知道谁发出了请求,并且它可以仅识别AJAX请求吗? - Peteris
会话认证由您自己负责。您可以给客户端一个密钥,每个请求都会传回该密钥。 - Diodeus - James MacFarlane
我真的找不到任何安全的解决方案。我考虑过发送客户端身份验证,但是客户端本身可以嗅探头文件并为自己重复使用密钥。必须有更强大的解决方案,因为所有 Web 应用程序都需要这个。 - Peteris
1
依赖于referer并不是一个好主意。另一方面,使用AJAX时用户不能通过其他方式复制任何操作。 - symcbean
伪造引荐来源相当容易。 - Enno

0
这是一个授权问题:只有经过授权的请求才能创建新用户。因此,当接收到这样的请求时,您的服务器需要检查它是否来自一个被授权创建新用户的客户端。
现在主要问题是如何确定哪些请求是经过授权的。在大多数情况下,这是通过用户角色和/或一些票务系统来完成的。使用用户角色,您将面临额外的问题,例如用户识别和用户认证。但如果这些问题已经解决,您可以轻松地将用户映射到角色,比如“Alice是管理员”和“Bob是普通用户”,只有管理员有权创建新用户。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接