在浏览器中破解JavaScript有多容易?


37

我的问题与JavaScript安全性有关。

假设您使用的是BackboneAngularJS之类的JavaScript框架的身份验证系统,并且您需要安全的端点。没问题,因为服务器始终是硬道理,并会检查您是否有权执行所需的操作。

但是,如果在不涉及服务器的情况下需要一点安全性怎么办?那可能吗?

例如,假设您有一个客户端路由系统,并且希望为登录用户保护一条具体的路由。因此,您对服务器执行ping操作,询问是否允许访问受保护的路由,然后继续。问题是,当您对服务器执行ping操作时,会将响应存储在一个变量中,因此,下次访问私有路由时,它将检查您是否已登录(不对服务器执行ping操作),并取决于响应会成功与否。

用户修改该变量并获得访问权限有多容易?

我的安全(和JavaScript)知识不是很好。但是,如果变量不在全局范围内并且在模块模式的私有部分中,该模式仅具有getter而没有setter,即使在这种情况下,您能否破解呢?


29
所有这些长答案。简而言之,为您解答标头,“非常容易入侵”。要相互内联回答您的前两个问题,“没有服务器,您就失去了安全性”和&“否”。回答第三个问题,“非常容易”,最后回答“是,轻松”。妳去 所有问题都回答了。:P
SpYk3HH 2013年

主要示例,请参阅我的博客文章有关将jQuery添加到任何网页。spyk3lc.blogspot.com/2013/05/…现在,年轻的padawan,继续尝试。看看将jQuery添加到尚无jQuery的站点有多么容易,然后使用jquery轻松地操作视线的任何部分而无需使用很多行的javascript。繁荣!
SpYk3HH 2013年

7
曾经,在注册域名时,电话号码是必填字段,但这仅在javascript中强制执行,而不是服务器端。因此,我通过重新定义功能(使用Firebug)禁用了它,瞧!他们没有我的电话号码。
Izkata

8
manipulate any part of the sight without long lines 现场与视线
mplungjan 2013年

8
专业的Web程序员需要正确处理此类事情。请。纳粹语法不只是令人尴尬:) plus.google.com/u/0/+MonaNomura/posts/h9ywDhfEYxT
mplungjan 2013年

Answers:


26

在阅读此答案之前,请先阅读Joachim的答案。他介绍了客户端漏洞背后的一般原因。现在,对于如何解决此问题的建议...

一种用于客户端-服务器通信的安全方案,而无需在每个请求上手动向服务器进行身份验证:

仍然让服务器拥有最后发言权,服务器仍然必须验证客户端说的所有内容,但这是透明发生的。

假定使用HTTPS协议来防止中间人攻击(MITMA)。

  • 客户端第一次与服务器握手,服务器使用非对称加密方案为客户端生成一个公共密钥并保留一个私有密钥。客户端将服务器的“公钥”存储在本地存储中,并使用您不会在任何地方保存的安全密码进行加密。

  • 客户端现在离线。客户端要执行受信任的操作。客户端输入他的密码并获取服务器的公共密钥。

  • 基于其数据的知识,现在客户端进行操作,并在客户端加密每次与服务器的公钥进行操作的客户端

  • 当客户端在线时,客户端发送其客户端ID,并将客户端执行的所有操作发送到使用服务器的公钥加密的服务器。

  • 服务器对动作进行解密,如果动作格式正确,它会相信动作起源于客户端。

注意:

  • 您不能将客户端的密码存储在任何地方,否则攻击者将能够获取密钥并对其进行签名。该方案的安全性完全取决于服务器为客户端生成的密钥的完整性。要求密钥时,客户端仍需要通过服务器进行身份验证。

  • 实际上,您仍然依靠服务器不是客户端来确保安全性。客户端执行的每个操作都必须在服务器上进行验证。

  • 可以在Web Worker中运行外部脚本。请记住,您现在拥有的每个 JSONP请求都是一个更大的安全问题。您需要不惜一切代价保护密钥。一旦丢失,攻击者就可以冒充用户。

  • 这可以满足您执行“不对服务器执行ping操作”的要求。如果攻击者不知道密钥,就不能简单地使用伪造数据模仿HTTP请求。

  • 约阿希姆的答案仍然正确的。实际上,您仍然在服务器上执行所有身份验证。您在这里保存的唯一一件事是每次都需要使用服务器进行密码验证。现在,当您要提交或提取更新的数据时,只需要涉及服务器即可。我们在这里所做的只是在客户端保存一个受信任的密钥,然后让客户端重新验证它。

  • 对于单页应用程序(例如,使用AngularJS),这是一种非常常见的方案。

  • 我将服务器的公钥称为“ public”,因为在RSA之类的方案中这意味着什么,但实际上,它是方案中的敏感信息,应加以保护。

  • 我不会将密码保留在内存中的任何位置。每当用户开始运行脱机代码时,我都会让用户提交“脱机”密码。

  • 不要使用自己的加密技术 -使用Stanford's等已知库进行身份验证。

  • 按原样接受此建议。在实际业务关键型应用程序中进行这种身份验证之前,请咨询安全专家。这是一个既痛苦又容易出错的严重问题。

这是至关重要的,没有其他的脚本访问该页面。这意味着您只允许Web Worker使用外部脚本。您不能相信用户输入密码时可能会截获密码的任何其他外部脚本。

如果不能完全确定并且不延迟其执行,请使用prompt不是内联密码字段(也就是说,不应将其保留到事件只能访问同步代码才能访问事件的地步)。并且实际上不要将密码存储在变量中-再次,这仅在您相信用户的计算机没有受到损害时才有效(尽管对于服务器验证也是如此)。

我想再次补充一点,我们仍然不信任客户。您不能单单信任客户,我想Joachim的答案就是如此。我们仅获得了不必在开始工作之前对服务器进行ping操作的便利。

相关资料:


3
“不要掷出自己的密码”与原始方法一样适用于协议,即使不是更多,因为人们通常不愚蠢地制作自己的原始方法,但他们认为他们可以创建一个很好的协议。我也看不到为什么在这里需要RSA。由于您使用的是HTTPS,为什么不只生成一个16-32字节的共享密码,并要求将其与将来的请求一起发送?当然,如果您这样做,请确保对字符串使用时不变的相等性检查...
Reid

2
+1 @Reid是的,最近我刚刚和一些专家讨论了这个问题。我在这里大致将原始方案基于我了解的协议(由Rabin IIRC撰写),但至少要等到找到具体信息为止(并举例说明为什么在这种情况下需要非对称加密)。在未事先咨询安全专家的情况下,请勿使用此答案中建议的方案。我已经在很多地方看到了这种方法,但是实际上这几乎没有什么意义。我还编辑了答案以增强这一点。
本杰明·格伦鲍姆

使用提示几乎没有安全性。攻击者可以覆盖此window.prompt方法以拦截密码短语,或启动自己的提示(可能在iframe中!)。密码字段还有一个好处:不显示字符。
Rob W

@RobW当然,如果页面被盗用,那么整个方案毫无用处。如果攻击者有权在页面中运行JavaScript,我们将被搞砸。提示背后的想法是,它被阻止了,但是您是对的,它提供的任何安全性益处都是令人怀疑的。请参阅列表中的最后一个链接。
本杰明·格林巴姆2013年

1
首先。很棒的答案,我想我不能要求其他任何东西。另一方面,我想为我做宠物项目(当然还有想使用它的人),也许这太过分了(也许不是)。我的意思是,我不想做任何严肃的事情,恐怕我无法进行您所解释的那种身份验证,缺乏知识。我想我会进行一次简单的401检查,或者如果我没有任何请求,则每次访问这种路由时,我都会ping服务器。身份验证令牌也是一个选项(也许与您在AFAIK此处解释的内容最接近)。谢谢您:)
耶稣·罗德里格斯

89

这很简单:当攻击者控制客户端时,任何依赖于客户端仅执行您要求的操作的安全机制都会受到损害。

可以对客户端进行安全检查,但只能有效地充当“缓存”(如果客户端已经知道答案将为“否”,则避免进行昂贵的服务器往返))

如果要保留一组用户的信息,请确保这些用户的客户端永远不会获得该信息。如果将“秘密数据”与说明“一起发送,但请不要显示”,则禁用检查该请求的代码将变得很简单。

如您所见,此答案并未真正提及任何JavaScript /浏览器细节。这是因为无论您的客户是什么,这个概念都是相同的。不管是胖客户端(传统客户端/服务器应用程序),老式Web应用程序,还是具有大量客户端JavaScript的单页应用程序,都没有关系。

数据离开服务器后,您必须假定攻击者拥有对该服务器的完全访问权限。


谢谢。如果您能进一步解释它,那将很可爱,我的安全知识不是那么好,我唯一了解的部分是我错了:P。当您谈论缓存时,仅当服务器拒绝时才进行缓存吗?我的意思是,如果服务器一次回答是,您将无法缓存,对吗?
耶稣罗德里格斯

3
我只想补充一点,那就是可以访问闭包变量在浏览器(就像你提到的模块模式),尤其是在调试器:)
本杰明Gruenbaum

2
@BenjaminGruenbaum:可以随意将其扩展为专注于JS方面的答案。我仅在此处给出了与技术无关的高级概述。侧重于JS本身的答案也将是不错的!
Joachim Sauer 2013年

1
简而言之,如果根据javascript变量可以访问某些信息/路由/任何内容,那么在任何情况下都不是安全的,因为您可以轻松地更改该变量以说出访问该私有内容所需的内容。
耶稣罗德里格斯

4
@JoachimSauer我认为那会错过您很好地提到的这个问题的要点。无论客户端采取何种安全措施,都有可能损害通信。您可以使用JavaScript创建非常可靠的身份验证系统,但是将通信插入到其他客户端也视为真实来源的服务器时,这一切都不值钱。源代码全部发送到客户端,聪明的攻击者可以读取它,然后向服务器模仿HTTP请求。除非在服务器上进行验证,否则必须将源自客户端的任何内容都视为不可信。
Benjamin Gruenbaum 2013年

10

游戏界有句谚语:“ 客户在敌人的手中“。在服务器等安全区域之外运行的任何代码都是易受攻击的。在最基本的情况下,易受攻击而无法首先运行。由客户决定实际运行您的“安全代码”,并且用户可能使用本机代码时,由于攻击者需要是一个很好的程序员来操纵它,因此您至少具有对组件的自动混淆和附加的保护层,而JS通常不会混淆并且是纯文本格式。进行攻击所需的只是诸如代理服务器和文本编辑器之类的原始工具,攻击者仍然需要一定程度的编程知识,但是使用任何文本编辑器修改脚本比将代码注入可执行文件更容易。


大会不是
一团糟

@miniBill:虽然经验丰富的攻击者在汇编代码方面不会有任何麻烦,但是它将提供一个非常基本的高通滤波器。(A,这是学术性的,因为淘汰脚本小子对于OP的场景提供了最小的安全性提高)
Piskvor 2013年

1

这不是黑客JavaScript的问题。如果我想攻击您的应用程序,我将使用一个私有代理,该代理将允许我捕获,修改和重播流量。您提议的安全方案似乎没有针对此的任何保护措施。


0

专门讲一下Angular:

保护路由客户端根本不存在。即使您“隐藏”该路线的按钮,用户始终可以输入该按钮,Angular也会抱怨,但是客户端可以对此进行编码。

在某个时候,您的控制器将不得不向您的服务器询问呈现视图所需的数据,如果用户无权访问该数据,则您将不会收到该数据,因为您已在服务器端保护了该数据,并且您的Angular应用应该可以正确处理401。

如果要保护原始数据,则不能在客户端,如果只希望特定用户只能以某种方式查看公共数据,请在服务器上创建数据“视图”而不是发送原始数据发送给客户端并对其进行重组(无论如何,出于性能原因,您应该已经这样做了)。

旁注:切勿在Angular请求的视图模板中内置任何敏感内容,只是不要这样做。如果出于某种疯狂的原因,则需要在服务器端保护这些视图模板,就像在进行服务器端渲染时一样。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.