如何在没有SSL的Web API上接受身份验证?

10 security authentication api

我正在构建一个非常类似于StackOverflow提供的Web API .

但是在我看来,安全性很重要,因为数据是私有的.

  • 我必须使用HTTP.
  • 我不能使用SSL.

你推荐我什么解决方案?

编辑:身份验证!=加密

Not*_*tMe 17

几乎每个公共API都通过为每个Web请求传递身份验证令牌来工作.

此令牌通常以两种方式之一分配.

首先,一些其他机制(通常登录到网站)将允许开发人员检索永久令牌以在其特定应用程序中使用.

另一种方法是根据请求提供临时令牌.通常,您有一个web方法,他们会在其中传递用户名/密码,并根据经过身份验证和授权执行任何API操作的情况返回有限使用令牌.

在dev拥有令牌后,他们会将其作为参数传递给您公开的每个Web方法.您的方法将在执行操作之前首先验证令牌.

作为旁注,你对"安全性很重要"的评论显然不是真的.如果是,那么你通过SSL做到这一点.

我甚至不认为这在任何情况下都是"最小"的安全性,因为它只是提供了一种错误的信念,即你有任何安全性.正如皮斯科夫所指出的那样,任何有兴趣的人都可以以某种方式倾听或打破这一点.


小智 16

首先,我建议你阅读这篇优秀的文章:http://piwik.org/blog/2008/01/how-to-design-an-api-best-practises-concepts-technical-aspects/

解决方案非常简单.它是Flickr(如基于令牌)和我使用的paiement网关使用的身份验证方法(高度安全)的组合,但使用私有密码/ salt.

为了防止未经授权的用户使用API​​而不必在请求中发送密码(在我的情况下,由于没有SSL而明确),他们必须添加一个签名,该签名将包含一个私有和串联的MD5哈希.公共价值观:

  • 众所周知的值,例如用户名甚至API路由
  • 用户密码短语
  • 用户生成的唯一代码(只能使用一次)

如果我们请求/ api/route /并且密码短语是kdf8*s @,则签名如下:

string uniqueCode = Guid.NewGuid().ToString();
string signature = MD5.Compute("/api/route/kdf8*s@" + ticks);
Run Code Online (Sandbox Code Playgroud)

然后,HTTP请求的URL将是:

string requestUrl = 
     string.Format("http://example.org/api/route/?code={0}&sign={1}", uniqueCode, signature);
Run Code Online (Sandbox Code Playgroud)

在服务器端,您必须使用相同的唯一代码阻止任何新请求.防止任何攻击者简单地重复使用相同的URL.这是我想避免的情况.

由于我不想存储API使用者使用的代码,我决定用刻度替换它.刻度表示自0001年1月1日午夜12:00:00起经过的100纳秒间隔的数量.

在服务器端,我只接受时间戳(时间戳),容差为+ -3分钟(如果客户端和服务器没有时间同步).意味着潜在的攻击者将能够使用该窗口重用URL但不能永久使用.安全性有所降低,但对我的情况仍然足够好.


Pis*_*3.0 6

简短的回答:如果它应该可以通过普通客户端(浏览器请求/ AJAX)使用,那么你就搞砸了.

只要您使用未加密的传输,攻击者就可以通过MITM攻击删除任何类型的页内加密代码.即使SSL也不能提供完美的安全性 - 但普通的HTTP需要一些页外特定的扩展.

HTTP仅提供传输 - 没有安全标识,没有安全身份验证,也没有安全授权.

示例安全漏洞 - 一个简单的HTTP页面:

<script src="http://example.com/js/superstrongencryption.js"></script>
<script>
  encryptEverything();
</script>
Run Code Online (Sandbox Code Playgroud)

这看起来安全的,但它有一个重大缺陷:你没有任何保证,在所有的,你的确文件加载superstrongencryption.js你的要求.与普通的HTTP,你发送请求的地方,和东西回来.没有办法验证它实际上是来自example.com,也没有办法验证它实际上是正确的文件(而不仅仅是function encryptEverything(){return true}).

也就是说,理论上你可以在你的HTTP请求和响应中构建非常类似SSL的东西:对每个请求进行加密加密和签名,与每个响应相同.你需要为此编写一个特殊的客户端(当然还有服务器端代码) - 它不适用于标准浏览器.