如何使用REST API进行身份验证? (浏览器+本机客户端)
我正在使用Rails构建一个Web应用程序。 目前,我正在使用HTTP协议设计Devise,这很容易设置,并且运行良好。
该应用程序由一个提供AJAX Web应用程序的URL组成。 其余的可用URL属于REST API。 所以一切和每一个小数据请求都是通过AJAX完成的。
现在我想扩展整个事情来支持本地客户端。 我读了很多关于无状态身份验证,http基本和摘要身份验证,http会话,cookie,xsrf等的内容......现在我觉得我不能拥有安全的应用程序,因为总有办法劫持它的某些部分。
1 .: HTTP会话比。 无状态身份验证令牌
有什么不同? 我不明白。
HTTP会话:
无状态身份验证令牌:
对我来说,这两种方式看起来很相似 使用Rails,我还可以选择将会话存储在数据库中...... Devise会对无状态身份验证令牌执行相同的操作。
2 .:认证方法
现在我用{"user":{"email":"e@mail.com","password":"p455w0rd"}}
使用POST /users/sign_in
。
但是还有其他的可能性,比如HTTP基本认证和HTTP摘要认证,还有像oAuth这样的解决方案(对我来说太大了)。
从我读过的内容来看:
POST /users/sign_in
和HTTP基本认证之间没有区别。 两者都使用明文。 我需要的:
want_to_change_password_salt
并使用它来加密客户端的密码。 但是 (?!)通过这种方式我发送了散列密码的重要部分加上散列密码。 听起来对我不安全?! 3 .: CSRF令牌
如上所述,现在我只有一个使用REST API的普通AJAX网站。 它具有XSRF保护:网站通过导轨交付,因此嵌入了XSRF令牌。 我使用AJAX阅读并在进行POST
时传输它。 然后,Rails返回请求的数据和一个新的XSRF标记,然后将它用于下一次POST
。
现在我想更改我的服务器应用程序以使用本机客户端。 本机客户端不会加载HTML页面,因此不会检索CSRF令牌。 所以我想到了以下选项:
POST
。 问题:
4:无状态身份验证令牌
在这里我主要有很多问题:
GET
参数,因此可以包含令牌。 user_id
expiration_date
user_id
, expiration_date
, SECRET_KEY
]的散列(或HMAC?)。 SECRET_KEY
基本上是由服务器生成的一个随机字符串。 对于huuge的帖子感到抱歉,但安全至关重要! 而且我不想犯可能暴露私人数据的设计错误。
谢谢 :)
这里有一些新的信息和新的问题;-)
:
5 .:本地客户
就本土客户而言,没有(简单)使用会话的方式:
本地客户端不是浏览器
因此它不会轻易处理cookie(并且没有cookie就没有典型的会话处理)
所以有三种可能的选择:
实施本地客户端的会话处理。 这将如下所示:
根本不要使用会话。 从本地客户的角度来看,它几乎与1:1相同。
混合方法。 这基本上意味着服务器必须区分浏览器和本地客户端,然后检查提供的会话ID和会话数据,或者(对于本机客户端)检查提供的身份验证令牌。
6 .:具有无状态的CSRF令牌(=无会话/无Cookie)授权
CSRF保护可以保护您的用户免受恶意网站的攻击,该网站尝试以您登录的用户的名义对您的API做出一些请求,但是没有您的用户知道。 使用会话时非常简单:
因此,攻击网站只需执行以下操作:
<form>
Submit
按钮 当然这个表格会是这样的:
<form action="http://your.api.com/transferMoney" method="post">
<input type="hidden" name="receiver" value="ownerOfTheEvilSite" />
<input type="hidden" name="amount" value="1000.00" />
<input type="submit" value="WIN MONEY!!" />
</form>
这导致了以下假设 :
CSRF保护仅仅是因为浏览器自动发送cookie。
本机客户端不需要CSRF保护(当然,您的浏览器无法访问您的本机应用程序的身份验证数据(令牌,Cookie,不管),并且您的本机应用程序不会使用浏览器与API通信)
如果你有一个不使用Cookies来验证用户的API设计,那么不可能做CSRF。 因为攻击者必须知道身份验证令牌并将其与恶意请求一起明确发送。
如果您想对应用程序进行安全保护,您当然可以使用CSRF令牌以及您的无状态身份验证机制,但我非常肯定,没有额外的安全增益。
7 .:选择正确的HTTP方法
登录/登录和退出/登出:
切勿使用GET
(至少)三个原因:
在大多数情况下,CSRF保护只保护POST,PUT,PATCH和DELETE,因此CSRF可在用户不知情的情况下使用GET请求登录用户
GET请求不应该改变应用程序的状态。 但是,即使用会话应用程序状态更改登录/注销,因为会话被创建或销毁。
当使用GET请求并将身份验证信息作为URL参数(例如http://your.api.com/login?username=foo&password=bar
)发送时,还有另一个问题:服务器日志! 大多数服务器只是记录每个包含所有URL参数的HTTP请求。 这意味着:如果你的服务器遭到黑客入侵,就不需要破解数据库中的密码哈希,他们只需要查看服务器的日志文件。 另外,恶意管理员还可以读取每个用户的登录信息。 解决方案:
login?username=foo&password=***
)。 但我建议,简单地使用请求主体和POST方法一起使用这种信息。 所以你可以使用例如:
POST http://your.api.com/authentication
登录
DELETE http://your.api.com/authentication
进行注销
8 .:密码和散列
身份验证仅适用于某些密钥。 当然这个密钥应该保密。 意即:
永远不要在数据库中以明文形式存储密码。 有几个库可用来保证安全。 在我看来,最好的选择是bcrypt
。
bcrypt :它已经过优化以哈希密码。 它会自动生成一个salt并多次散列密码(轮次)。 另外,生成的哈希字符串包含所需的所有内容:循环次数,盐和哈希。 虽然你只需要存储这一个字符串,并且不需要手工写任何东西。
当然你也可以使用其他强大的哈希库。 但是对于其中的大多数人来说,你必须实施腌制并自己使用超过1轮。 此外,他们不会像bcrypt那样给你一个单一的字符串,尽管你必须管理自己存储轮次,盐和散列,然后重新组合。
轮次 :这只是密码被散列的频率。 当使用5000轮时,散列函数将返回密码散列哈希散列的散列值。 基本上有这样一个原因:它会消耗CPU的功率! 这意味着:当有人试图强制你的散列时,使用5000轮时需要更长的时间5000倍。 对于你的应用程序本身并不重要:如果用户知道他的密码,他不会识别,如果服务器需要0.0004ms或2ms来验证它。
好的密码 :如果密码太简单,最好的散列函数是无用的。 如果可以使用字典进行破解,使用字典进行破解并不重要:它可能需要几个小时的时间才能完成,但是如果可能需要几个月或几年,几个小时的时间又会是多少? 虽然请确保您的用户密码包含通常的建议(低+大写+数字+特殊字符等)。
9 .:通过电线发送加密密码
如果您不能(或不想)依赖HTTPS,但不希望在登录时以明文方式发送密码,则可以使用非对称密码术(http://en.wikipedia.org/wiki/Public -key_cryptography)。
该服务器创建密钥对(公钥和私钥)。 公钥被提供给客户,私钥必须保密!
客户端现在可以使用公钥对数据进行加密,并且只能由私钥所有者(=服务器)解密此数据。
这不应该使用(!)将密码存储在数据库中,因为如果您的服务器被黑客入侵,黑客将拥有加密的密码和用于解密的私钥。 尽管继续使用一些散列算法(如bcrypt)将密码存储在数据库中。 另一个原因是,如果您认为某人破解了您的加密密码,您可以轻松生成一个新的密钥对。
HTTPS基本上以相同的方式工作。 但是,如果您的应用程序使用HTTPS(建议使用HTTPS),则在安全性方面可能没有太大好处。 但是如上所述,如果您因任何原因无法使用HTTPS,或者不信任它,那么您就可以构建自己的安全连接。
请记住,真正的HTTPS连接会加密整个(!)连接和所有数据,而不仅仅是密码数据。 它可以从客户端到服务器端以及服务器端到客户端两种方式进行加密。
链接地址: http://www.djcxy.com/p/505.html上一篇: How to do authentication with a REST API right? (Browser + Native clients)