安全地从jQuery调用安全的WebService

时间:2014-06-02 07:28:47

标签: jquery .net ajax security

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

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

我目前的计划是:

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

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

处理身份验证的最佳方法是什么,理想情况下无需购买SSL证书(数据本身不是特别敏感)。 ?

4 个答案:

答案 0 :(得分:7)

除了明显的理由为什么强烈建议使用SSL,如果可能,你绝对应该使用它,你可以考虑通过哈希登录和密码来提高安全性。

哈希以一种非常难以破解的方式工作 - 非常相似的字符串的哈希值完全不同,即使您只更改了一个字符。见:

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

这表明您需要一个确切的密码(或它的哈希冲突,这是很难计算的)才能打破&#39;哈希,以及&#39; simmilar&#39;一个是完全没用的。

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

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

(您可以保留未散列的登录名,仅用于调试/维护目的。)

之后,在你的应用程序中连接到Web Service之前,你完全一样,但是在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)连接仍然不安全且易于嗅探。

答案 1 :(得分:3)

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

  1. 服务器向浏览器发送(随机)“质询文本”
  2. 浏览器执行一些预先确定的修改,涉及来自密钥的位,并将其发送到散列函数,并将“响应文本”发送到服务器
  3. 服务器执行相同的预定修改,涉及来自密钥的位(在此方案下必须存储为纯文本),还将其发送到散列函数,并将其结果与由浏览器
  4. 如果浏览器提供的和服务器提供的哈希匹配 ,那么显然,客户端知道与服务器相同的密钥,因此分配会话(使用Cookie) ,就像世界其他地方一样),让他们进来。
  5. 这个方案确实有一些缺点,特别是:

    • 必须在服务器的数据库上保留未经过修改的密码(如果您的客户在其他地方重新使用密码,那么这只是一个问题)
    • 使用低熵密码作为它们的密钥会削弱加密的加密强度(如果你确定的中间人是加密精明的话,那真的只是一个问题)
    • 您的服务器可能会非常快速地耗尽随机性,生成挑战文本,如果它必须为大量登录服务

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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