我们目前正在开发一个非常简单的Web应用程序,我们希望“混淆”(什么是正确的术语?)或以某种方式编码请求参数,这样我们就可以减少机会空闲用户发送任意数据。
例如,网址看起来像/webapp?user=Oscar&count=3
我们想要像/webapp?data=EDZhjgzzkjhGZKJHGZIUYZT
这样的东西,并在服务器中使用真实的请求信息解码该值。
在我自己实施这样的事情之前(可能做错了)我想知道是否有事情要做?
我们在服务器上有Java,在客户端上有JavaScript。
答案 0 :(得分:28)
不,不要这样做。如果你可以在客户端代码中构建一些东西来混淆传输回服务器的数据,那么一个故意的黑客也是如此。无论您的官方客户端做什么,您都无法信任发送到您服务器的数据。 坚持转发客户端数据并根据服务器端的白名单进行验证。使用SSL,如果可以,请将请求参数放在POST而不是GET。
扩展编辑
您的困惑源于阻止用户篡改请求数据的目标,需要实施标准安全措施。 Web应用程序的标准安全措施涉及使用身份验证,权限和会话管理,审计跟踪,数据验证和安全通信渠道的组合。
使用SSL并不会阻止客户端篡改数据,但它确实阻止了中间人查看或篡改数据。它还指示行为良好的浏览器不要在URL历史记录中缓存敏感数据。
看起来你有一些没有身份验证的简单Web应用程序,并传递了在GET中控制它的请求参数,因此一些非技术精明的人可能会发现user=WorkerBee
可以只需在浏览器栏中更改为user=Boss
,这样他们就可以访问他们看不到的数据,或者做他们不应该做的事情。 你希望(或顾客的愿望)模糊这些参数是天真的,因为它只能挫败技术上最不精明的人。这是一个半生不熟的措施,你没有找到现有解决方案的原因是它不是一个好的方法。你最好花时间实现一个体面的认证系统和审计跟踪(如果这确实是你做的那样,将Gary's answer标记为正确)。
所以,把它包起来:
答案 1 :(得分:12)
如果您的目标是“减少空闲用户发送任意数据的机会”,那么我会尝试另一种更简单的方法。创建一个私有加密密钥并将其存储在应用程序服务器端。每当您的应用程序生成URL时,使用您的私有加密密钥创建URL的哈希值,并将该哈希值放入查询字符串中。每当用户请求包含url中参数的页面时,重新计算哈希并查看它是否匹配。这将确保您的应用程序计算网址。它会使您的查询字符串参数可读。在伪代码中,
SALT = "so9dnfi3i21nwpsodjf";
function computeUrl(url) {
return url + "&hash=" + md5(url + SALT );
}
function checkUrl(url) {
hash = /&hash=(.+)/.match(url);
oldUrl = url.strip(/&hash=.+/);
return md5(oldUrl + SALT ) == hash;
}
答案 2 :(得分:6)
如果您尝试限制对数据的访问,请使用某种登录机制和cookie,提供单点登录身份验证密钥。如果客户端使用密钥发送cookie,则他们可以根据与其帐户相关联的权限(管理员,公共用户等)操纵数据。只需看看Spring Security,CAS等,就可以在Java中轻松使用它。 cookie中提供的令牌通常使用发布服务器的私钥加密,通常是防篡改。
或者,如果您希望公共用户(未经身份验证的)能够将某些数据发布到您的网站,那么所有投注都将被取消。您必须在服务器端进行验证。这意味着限制对某些URI的访问并确保清除所有输入。
这里的黄金法则禁止一切,除了你知道的东西是安全的。
答案 3 :(得分:3)
如果目标是防止“静态”URL被操纵,那么您可以简单地加密参数或签名。它可能“足够安全”来处理URL参数的MD5以及一些盐。例如,盐可以是存储在会话中的随机字符串。
然后你可以:
http://example.com/service?x=123&y=Bob&sig=ABCD1324
这种技术暴露了数据(即他们可以“看到”xyz = 123),但他们无法改变数据。
“加密”有一个优点(我松散地使用该术语)。您可以在此处加密URL的整个参数部分。
您可以在这里执行以下操作:
http://example.com/service?data=ABC1235ABC
使用加密的好处是双重的。
它保护数据(例如,用户永远不会看到xyz = 123)。
另一个特点是它可以扩展:
http://example.com/service?data=ABC1235ABC&newparm=123&otherparm=abc
在这里,您可以解码原始有效负载,并与新数据进行(安全)合并。
因此,请求可以将数据添加到请求中,而不是更改现有数据。
您可以通过签名技术执行相同的操作,您只需要将整个请求合并到一个“blob”中,并且该Blob是隐式签名的。这是“有效”加密的,只是一种弱加密。
显然你不想在客户端做任何这样的事情。毫无意义。如果你能做到,“他们”可以做到而且你无法区分,所以你可能根本就不去做 - 除非你想通过普通的HTTP端口“加密”数据(vs TLS,但是人们会明智地想知道“为什么要这么麻烦”。)
对于Java,所有这些工作都在Filter中,就像我这样做。后端与此隔离。
如果您愿意,可以使用出站过滤器使后端与此完全隔离,该出站过滤器在出路时处理URL加密/签名。
这也是我所做的。
不利的一面是它使得它正确且高效。你需要一个轻量级的HTML解析器来提取URL(我写了一个流式解析器来实现它,所以它没有将整个页面复制到RAM中。)
光明的一面是所有内容方面都“正常”,因为他们对此一无所知。
在处理Javascript时还有一些特殊处理(因为您的过滤器不会轻易“知道”哪里有加密的URL)。我通过要求将URL签名为特定的“var signedURL ='....'”来解决这个问题,因此我可以在输出中轻松找到它们。并不像你想象的那样压倒设计师的负担。
过滤器的另一个亮点是你可以禁用它。如果您发生了一些“奇怪的行为”,只需将其关闭即可。如果行为继续,您会发现与加密相关的错误。它还允许开发人员以纯文本格式工作,并保留加密以进行集成测试。
痛苦,但最终总体上很好。
答案 4 :(得分:1)
像jCryption这样的东西?
答案 5 :(得分:0)
您可以使用base64或类似的东西对数据进行编码。我会用JSON编码自身中的参数来序列化它们。