【问题标题】:Calling a secured WebService from jQuery safely安全地从 jQuery 调用安全的 WebService
【发布时间】:2014-06-02 07:28:46
【问题描述】:

我有一个 WebService,它有几个只对站点成员可用的调用。我想构建一个纯 html/jQuery 移动应用程序,它可以调用此服务发出请求和下载信息。

我最初的计划是将用户的用户名和密码放在 auth 标头中,但我担心将它们暴露给任何流量嗅探器。我显然可以创建一个会话密钥,因此在初始身份验证后他们使用令牌调用,但这可能容易受到会话窃取。

我目前的计划是:

  • 实现登录调用,这将返回一个令牌,该令牌将在指定时间后过期
  • JS 使用此令牌调用(从而减少发送密码的次数)。
  • 用户拨打电话
  • 将令牌与用户的 IP 地址进行比较。
  • 用户注销,这将结束会话并提前移除密钥以降低风险

另一个想法是在我发送密码时对其进行加密。基于 .NET RSACryptoServiceProvider 实现在 JS 中进行公钥/私钥加密是否可能/明智?

处理身份验证的最佳方法是什么,最好不要购买 SSL 证书(数据本身并不是特别敏感)。 ?

【问题讨论】:

  • 如果你真的想防止所有中间人攻击(强烈推荐,因为它是一个移动应用程序),你真的应该使用 SSL .您应该保护连接的传输层。
  • @Liath 虽然散列是一个很好的方法,但使用 SSL 仍然更好 - 正如我所说,它保护了整个传输层,不仅登录/密码/会话密钥,而且您的所有网络服务连接。
  • @Liath 发表了答案,希望对您有所帮助;)
  • SSL 是解决此问题的唯一解决方案。使用客户端加密,您必须向客户端(以及介于两者之间的任何人)公开您的密钥、盐和加密算法,这使得在网络上解密您的数据变得非常简单,从而使加密无用。
  • 强烈同意@Liam:您的问题基本上是“既然我已经排除了解决我问题的唯一实际解决方案,我该如何解决我的问题?”你不能,所以我什至不会费心浪费你的时间。要么数据足够敏感以保证适当的安全预防措施,要么在这种情况下,当您可以添加其他功能(或在吊床上打盹)时,不要花费您自己的宝贵时间来伪造系统安全。跨度>

标签: jquery .net ajax security


【解决方案1】:

除了强烈推荐 SSL 的明显原因,如果可能的话你绝对应该使用它,你可以考虑通过散列你的登录名和密码来提高你的安全性。

哈希以一种很难破解的方式工作 - 非常相似的字符串的哈希完全不同,即使您只更改一个字符也是如此。看到:

Login: "jacek", SHA1: "9749d1492af3d43f9c09e04c5c43f27bb909af51"
Login: "Jacek", SHA1: "46c676716f0e9aa86545c034d0e22a114d7cd488"

这表明你需要一个精确的密码(或者是哈希冲突,很难计算)来“破解”哈希,而“类似”的密码完全没用。

您的实现可能是这样的: 当您创建用户(例如注册时刻)时,您会计算登录名和密码的哈希值。之后,在 DB 中,您将拥有:

Login  | HashedLogin                              | HashedPassword 
---------------------------------------------------------------------------------------------
jacek  | 9749d1492af3d43f9c09e04c5c43f27bb909af51 | e4e088f4eaa96db85e11ba491a189f96f2e11793

(您可以保留未经哈希的登录仅用于调试/维护目的。)

之后,在您的应用中连接到 Web 服务之前,您所做的完全相同,但在 jQuery 中:

var _HashedLogin = Sha1_Hash($("#login").text());
var _HashedPassword = Sha1_Hash($("#password").text());

有很多第三方 SHA1 库,使用其中任何一个;)

然后,当您将信息发送到您的网络服务时,只发送散列值。 即使有人嗅到你的 ajax 调用,他也只会得到类似的东西:

"UserInfo":
{
    "login" : "9749d1492af3d43f9c09e04c5c43f27bb909af51",
    "pass" : "e4e088f4eaa96db85e11ba491a189f96f2e11793"
}

这对小偷没用,但您可以轻松地将这些值与数据库中预先计算的哈希值进行比较。你可以运行

select id from Users where HashedLogin = 'login_from_your_ajax_call' and HashedPassword = 'pass_from_your_ajax_call';

如果您收到此查询的任何结果,则说明您的安全验证已完成并且您拥有用户 ID。如果没有结果,则登录名或密码无效。

SHA1 对于家庭和半专业的原因来说是相当安全的,要计算一个会与您的密码冲突的哈希,您可能需要最多 2^61 比较。家用电脑要花上好几年的时间才能打破这一点。该解决方案仍然容易受到中间人攻击,但与发送明文身份验证数据相比,安全性有了飞跃。

另外,请记住,即使用户通过身份验证,除非您使用 SSL,ALL 其他 (client <-> Web Service) 连接仍然不安全且易于嗅探。

【讨论】:

  • 很好的尝试,但散列登录/密码远非“对小偷无用”。他下次记住这些,SELECT 语句也会通过他。
【解决方案2】:

如果您可以在浏览器/手机中访问 SHA_1 哈希函数,那么您能做的最好的事情是:

  1. 服务器向浏览器发送(随机)“挑战文本”
  2. 浏览器执行一些涉及密钥位的预先确定的修改,并将其发送到哈希函数,并将“响应文本”发送到服务器
  3. 服务器执行相同的预先确定的修改,涉及密钥中的位(在此方案下,它必须以纯文本形式存储),还将其发送到散列函数,并将其结果与由浏览器
  4. 如果浏览器提供的和服务器提供的哈希匹配,那么很明显,客户端知道与服务器相同的密钥,所以分配会话(使用 Cookie,如世界其他地方都会这样做),然后让他们进来。

这个方案确实有一些缺点,特别是:

  • 必须在服务器的数据库中保留未经哈希处理的密码(只有在您的客户端在其他地方重复使用密码时才是真正的问题)
  • 使用低熵密码 as 他们的密钥会削弱加密的加密强度(只有在中间有决心的人精通密码时才会真正成为问题)
  • 您的服务器可能很快就会耗尽随机性,生成质询文本,如果它必须为大量登录提供服务

如果您选择不使用密码本身作为密钥,那么您就只能使用公钥加密。 SSL 是一种强大、方便且广泛可用的公钥密码系统。它可能非常便宜——一些 CA 会免费为您提供经过域验证的证书。此时,您已经问自己希望通过使用浏览器提供的公钥密码系统获得什么。 Javascript 公钥加密库的缺乏可能反映了大多数有资格编写公钥库的人心中的这个问题。

【讨论】:

  • +1 用于提及会话密钥,这是我在回答中跳过的内容。但是,我仍然认为存储明文密码是不明智的 - 不幸的是,用户(尤其是非高级用户)倾向于在许多服务中使用相同的密码(或一个密码的变体)。
  • @Kamil 你是对的——如果用户不能存储经过加盐和散列的密码,那将是不礼貌的。正如几乎每个人都说的那样,公钥加密是真正的解决方案。 OP 需要代表他的用户(以值得信赖的方式处理他们的密码)和代表他自己(防止对受保护服务的欺诈性使用)决定他愿意接受的风险级别。您的解决方案有利于用户凭据的机密性,但会增加欺诈风险。矿井打击欺诈,但可能会使用户面临更大的风险。
【解决方案3】:

一种方法是使用类似 SSO 的机制。

  • 所以你有一个单独的域/网站说 www.myOwnSSO.net 对ALL您的移动应用程序和其他应用程序的用户进行身份验证。
    1. 此 www.myOwnSSO.net 将颁发令牌并重定向到您的不安全站点。
    2. 您的网站将在首次成功登录尝试时将此令牌发送给客户端。
    3. 对于您的服务器的每次后续调用,客户端都会在请求标头中包含此令牌。
    4. 在您的服务器上,您要做的第一件事是让 myOwnSSO 检查令牌到期时间。
    5. 如果令牌仍然有效,则处理请求。
    6. 如果令牌过期,您将移动客户端重定向到登录页面。并从上面的第 2 点开始。
    7. 如果令牌无效(即可能是某些请求伪造),请采取适当措施。

这样做的好处是,SSL 的成本是合理的,因为它适用于所有应用程序;同时,您不那么敏感的应用程序不在 https/SSL 上。

【讨论】:

  • OAUTH 协议正是针对这种情况。您甚至不必构建/操作 myownsso.net - 它可以是 Google 或其他提供商。它旨在让互联网用户和应用程序作者的生活更轻松。但是,我不太确定它是否能够“明确”地发行代币。需要 SSL 证书并不是回避。
  • @DavidBullock 同意 OAUTH 协议。如果这是可以使用的选项。但是,Liath 需要 SSL 仅用于身份验证数据,而不是真正的应用程序,正如他所明确指出的那样,应用程序没有任何敏感数据。
  • 您的回答很好(在那里,我现在赞成)-指向 OAUTH 的指针只是对 OP 的一点额外提示,即您的这种好方法可以通过很少的工作来实现,并且值得看看现有的选项。我不知道现实世界的 OAUTH 基础设施是否需要使用 SSL 来将会话密钥传输到应用程序。这在逻辑上是可以想象的,并且据我所知在实践中可能很常见,但我会感到惊讶。我不太理解 OP 不愿意使用真正的 SSL 证书,他也没有选择详细说明。
【解决方案4】:

如果数据不是特别敏感,则不要发明自行车,而是将 SSL 与self signed certificate 结合使用。可能,Web 服务最简单的身份验证方法是Basic access authentication。通过 SSL 发送每个请求的用户名和密码,没有麻烦。成功登录后将其从服务器发送回客户端,并将用户凭据存储在客户端的 local storage 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-04
    • 2014-02-08
    • 2018-04-11
    • 1970-01-01
    • 2012-06-30
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多