成为一个"认证”老司机
本文翻译自Auth-Boss。 如果有翻译的不恰当或不对的地方, 欢迎指出。
成为一个认证老司机, 了解网络上不同的身份认证方法。
本文档的目的是记录和编目Web上的身份验证方法。
认证指的是创建一个系统的过程,用户可以通过该系统“登录”在线服务,并授予对受保护资源的访问权限。
以下引用可能更好地总结我想要解释的内容:
客户端认证涉及向Web上的服务器证明客户端(或用户)的身份。[1]
Who
我是一个自学成才的开发人员,热爱开源技术,学习,指导和知识共享。
Why
我写这篇指南,因为关于验证这方面的信息很难直接找到。我决定戴上我的“研究帽“,做一些跑腿的工作。
How
我写作风格简洁,会用到一些技术词。
免责声明:本文档不作为包含所有认证方法的网络的目录;
本文档也不旨在提供“最佳”认证方法。
没人给钱贿赂我。
如果你想赞助我那更棒, 可以用一些其它方式, 比如领养一只小狗,或者帮助正在辛劳的人们。
引文:这些引文表示我引用的来源。
如果你想让我收下链接/更好地引用我的来源(不仅仅是一个链接到原始发布),我可以这样做。
如果你想让我更好的引用引文, 我当然愿意,不过请先让我知道<3。
遗漏,错误:
犯错并不罕见,我并不是安全方面的专家
如果你看到一些可以改进的东西请PR,告诉我哪里弄错了,我可以改进。
有关PR更多的信息,请查看CONTRIBUTIONS.md。
假想案例
我将使用本文档中的一个常见示例来说明在“客户端”(用户在其计算机前面)和“服务器”(后台)上发生的情况的登录流程。
我们的例子将会有一个想象的朋友:Beorn。
Beorn喜欢针织,经常去http://knittingworld.com购买用品。
Beorn在knittingworld有一个帐号,我们将看到他登陆的例子。
一般最佳做法
在讨论用于管理身份验证的技术之前,以下是你不应该做的。
以下某些项目可能不直接与登录/身份验证/用户注册有关,但通常有用。
切勿将密码存储为数据库中的纯文本。
不要写自己的哈希算法(除非你真的很聪明)
不要写自己的认证技术(再次,除非你真的很聪明)。
使用HTTPS。
一些忠告
我们还发现许多网站设计自己的身份验证机制,以提供更好的用户体验。
不幸的是,设计师和实现者通常没有安全背景,因此不能很好地理解他们可以使用的工具[2]
术语
web验证开发领域中有相当多的术语。
下面是一个术语列表,您将在下面看到。
HTTP 超文本传输协议。
这是一个大的概念。我只能简单的解释一下它的含义。
Web是围绕HTTP构建的 - 它是用于在Web服务器和用户之间通信的协议。
您的浏览器被视为HTTP客户端,因为它向HTTP服务器发送请求。
你的客户可以做很多不同类型的请求, - 你可能听说过一些最流行的请求 - POST POST PUT和DELETE。
HTTP服务器向您的浏览器 - 客户端发送响应。
这些响应就是资源。
资源可以是(但不限于):HTML文件,图像,文本,JSON等。
你可以认为资源是从服务器返回的“文件”。
关于此主题的其他链接:
HTTP Made Really Easy
RFC2616 - 这是一个关于HTTP的文档规范。
它被列为过期,但也列出了取代它的文档。
HTTPS
HTTPS是安全的HTTP。
它与SSL / TLS密切相关。
最初在互联网上的支付交易很受欢迎,最近变得越来越普遍。
您可能会认为https是“在浏览器中显示在我的网址左侧的绿色文本”;
经常伴随着锁的图标或类似的东西。
HTTPS是用TLS(或在过去的日子里,SSL)封装的HTTP,以保护浏览器和服务器之间的流量。
HTTPS会对与您的HTTP请求一起发送的信息和发回的响应进行加密。
这在我们开始谈论身份验证时尤其重要!
来自维基百科:
HTTPS在不安全的网络创建安全通道。
这确保了合理的保护免受窃听者和中间人攻击,只要使用足够的密码套件并且服务器证书被验证和信任。
TLS / SSL
TLS和SSL是加密协议。
TLS和SSL加密您通过网络发送的数据 - 它旨在防止人们“窃听”或篡改您要发送的数据。
SSLv2和v3今天被视为不安全(请参阅POODLE),因此大多数HTTPS是使用TLS 1.2完成的。
YouTube上有一些有用的视频,有助于解释这些复杂的问题,
这个视频MIT opencourseware挺不错的!
State
state
,stateful
,stateless
和piece of state
。
这些是术语,它们的定义不同。
在本文里,“piece of state”或“stateful”描述了一块存储在内存中的数据。
HTTP请求通常被描述为“stateless”。
当您访问网站和登录时,您正在传递一些信息以及您的HTTP请求, 用来标识您的身份。
无论你需要使用什么身份验证方法来识别自己,都必须“附加”到某个或另一个HTTP请求,因为你不能简单地将该状态放在HTTP协议本身中 - 必须采取另一种形式,可以凌驾于HTTP协议之上(正如你会看到在本文档的其余部分。)。
可能有点夸张... 我认为这篇来自苏格兰的文章解释的很不错The Ins and Outs of Token Based Authentication。
由于HTTP协议是无状态的,这意味着如果我们使用用户名和密码验证用户,那么在下一个请求,我们的应用程序将不知道我们是谁。
我们必须再次验证。
Cookies
Cookie是存储在用户浏览器上的小数据。
Cookie与HTTP相反,是有状态的 - 这意味着尽管HTTP不能存储用户信息,但是cookie可以。
网络Cookie的常见示例:
Beorn访问http://knittingworld.com为他的下一个针织项目购买一些不错的纱线和材料。
他登录后向他的购物车添加了三件商品。突然他听到一声砰!
并意识到他的微波炉里还有一罐金枪鱼。不好!
Beorn关闭了浏览器,立即忘记了他购物车里的东西,跑去检查微波炉。
罐头金枪鱼的酱汁已经洒在他家的地板上,Beorn回到他的电脑前,并重新访问https://knittingworld.com ...想看看他之前加入购物车的商品还在不在。
Cookies。
有不同种类的Cookies。
有些Cookie会在您的浏览器中停留多天,而其他Cookie会在您关闭浏览器后立即消失。
Cookie在过去(仍然是)认证中起到了很大的作用。
Web服务器通常使用认证cookie来确定用户是否登录以及他们有权访问哪些资源。
持久性cookie有时会带来麻烦,因为它们可以被广告商用来记录关于用户的web习惯的信息。
另一方面,它们通常用于保存用户每次访问站点时不必重新输入其登录凭证。
您可以通过导航到您的(使用Chrome)开发者工具并打开网络标签查看与请求一起发送的Cookie。
刷新页面将显示传入资源的列表,您可以选择其中的一个。
滚动列表, 看看找得到cookie不!
您也可以在开发人员工具的[Application]标签中查看Cookie 的相关信息。
Sessions / Session Management
我并不会一开始就去尝试简单的描绘出sessions,我会引用OWASP:
网络会话是与同一用户相关联的网络HTTP请求和响应事务的序列。
现代和复杂的web应用程序需要在多个请求期间保留关于每个用户的信息或状态。
因此,会话提供了建立变量的能力,例如访问权限和本地化设置,这将适用于在会话期间用户与webApp的每一次交互。
您可以在下面的“Methodologies”部分找到基于会话身份验证的示例。
关于Sessions的更多链接:
How does a web session work
What are web sessions?
Methodologies
以下是用于建立认证的技术方案列表。这不是一个完整的列表!
HTTP基本认证
HTTP基本身份验证(或“基本身份验证”)已经存在了很长时间。看起来人们倾向于使用它,因为它的简单性,它支持跨浏览器。这是一个空白页面,要求基本的验证。这里将演示如何确保webApp正常运行当Beorn关闭游览器重新再打开后:
Beorn去http://knittingworld.com 买纱线。
在挑选出纱线后,他点击“购买”按钮购买。
他的浏览器发出一个GET请求,服务器响应401告诉他需要验证。
Beorn在他的用户名和密码中输入登录表单。
在他点击登陆后,他的浏览器会发起GET(POST)请求, 并在请求头里带着Authorization。Authorization请求头类似于这样
Authorization:QWxhZGRpbjpvcGVuIHNlc2FtZQ==
服务器继续验证身份验证头并确定Beorn是否可以可以提交购买操作。浏览器会记住Authorization,之后的每一次游览器提交的请求,都会在请求头里加上
Authorization:QWxhZGRpbjpvcGVuIHNlc2FtZQ==
, 直到游览器关闭。
关于HTTP基本身份验证的一些重要注意事项:
上面的示例授权头部看起来不像用户名和密码,但是这是因为它是base64编码。它没有加密。
如果使用HTTP基本认证,请使用HTTPS。如果使用HTTP,身份验证凭据将作为明文发送到服务器。这不好。用户的用户名和密码通过线路仅作为base64编码文本发送 - 这对于解码来说很简单。通过使用HTTPS / TLS,您确保从客户端发送到服务器的数据被加密。
HTTP基本验证由游览器实现,今天很少使用。
基本验证使用API的基本认证,当与令牌组合时,(稍后讨论)只是一个授权报头,是完全合理的。它有额外的好处,不需要API客户端维护一个额外的会话cookie,并且,因为大多数系统日志查询参数而不是标题,将不会被默认记录。
基本验证与Token组合的时候, 好处很多,比如不需要客户端单独维护一个cookie, 并且也不会被客户端记录。
链接
Basic Authentication on OWASP
Why does stripe use HTTP basic auth with a token instead of the header
基于Session的认证
Session认证已经存在了一段时间,并且平常用的比较多。基于session的身份验证的关键是,用户的登录与服务器上的内存的一段状态或key-value存储(如Redis中)相关联。
让我们看看我们的朋友Beorn使用基于session的身份验证的示例。
Beorn去http://knittingworld.com 买一些东西。
当Beorn登录时,他将他的凭据发送到服务器。
当凭据到达服务器时,服务器以这种方式或另一种方式需要检查Beorn是否是其数据库中的用户。在这一点上,Beorn还没有登录。
Beorn的凭据匹配成功,所以他可以登录。
Beorn需要一些东西来识别他对服务器的未来请求 - 特别是如果他想要购买东西(必须登陆才能买)。这就是认证session的思想。
现在服务器知道Beorn是谁,并且已经将他识别为数据库中的用户,服务器将向他(或“返回”)发送一个cookie,这可以将Beorn列为在以后的请求中是已经登陆的用户。
现在,Beorn已经验证,并在他的浏览器上有一个session cookie(cookie的一种)。
当Beorn转到页面http://knittingworld.com/great_deals.html 他正在做另一个HTTP请求 - 但这次,他的session cookie将放在HTTP请求头里发送到服务器。
服务器将根据与内存中Session信息匹配的cookie进行身份验证(可以用redis,memcache等数据库来保存)
当Beorn从http://knittingworld.com 退出时,他在服务器(或Redis等)上的会话实例将过期,他的会话cookie也会过期。
基于Token的认证
基于令牌的认证已经变得更加普遍最近随着RESTful API的应用,单页应用程序和微服务的兴起。
什么是token?
token是一小块数据。
利用基于Token的认证的认证系统意味着用户向服务器发出的请求携带token以执行认证逻辑。当发出HTTP请求时, token是验证用户是否有资格访问资源的凭证。
这与基于Cookie的身份验证有何不同?
token认证是无状态的,而基于session的认证意味着在您的服务器(或在Redis等)中的某个地方保存着状态用以识别用户。
Auth0的博客文章Cookies vs Tokens:The Definitive 描述了cookie和令牌之间的身份验证流程的差别的:
基于session的认证流程:
1. 用户输入其登录信息
2. 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中
3. 具有sessionID的Cookie将放置在用户浏览器中
4. 在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求
5. 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁
基于令牌的认证流程:
1. 用户输入其登录信息
2. 服务器验证信息是否正确,并返回已签名的token
3. token储在客户端,最常见的是存储在`local storage`中,但也可以存储在session存储或cookie中
4. 之后的HTTP请求都将token添加到请求头里
5. 服务器解码JWT,并且如果令牌有效,则接受请求
6. 一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。
哇标记听起来很酷。他们比基于session的身份验证更好吗?
问错人了,伙计。我只是告诉你存在这个验证方式。我不会比较没有意义的比较,我尽最大努力做到这一点。有关更多有趣的免责声明,请访问上面的免责声明部分。令牌的类型一些常见的令牌包括JWT(下面讨论),SWT(简单网络令牌)和SAML(安全断言标记语言)
链接
Token Based Authentication - Implemenation Demonstration - W3
What is token based Authentication - SO
Token Based Authentication Made Easy
The Ins and Outs of Token Based Authentication
Cookies vs Tokens: The Definitive Guide (opinionated)
JWT
JWT代表“JSON Web Token”。 JWT是一种基于Token的认证。 JWT基于Web标准。现在JWT用的越来越多;JWT是Token认证的一种,所以说JWT基于Token的认证。再次,基于Token的认证的不同方法具有不同的优点和缺点。因此,上面的基于令牌的认证部分中的很多信息适用于此。
来自JWT RFC 7519标准化的摘要说明:JSON Web Token(JWT)是一种紧凑的,URL安全的方式,表示要在双方之间传输的声明。
JSON Web令牌是一个字符串。它可能看起来像这样:
eyJhbGciOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
上面的字符串是你在使用JWT执行身份验证时可能看到的;它是在认证时从服务器返回的凭证。JWT经过验证并且安全,因为它们使用私钥进行“数字签名”,并使用密钥进行身份验证。
JWT的结构?
JWT是一个自包含的数据块。每个JWT由payload
和signature
组成。当您的服务器创建token时,您还可以为token分配唯一的数据,可以在前端使用。这可以用于保存稍后进行其他数据库调用的需要。你仍然应该警惕在发送给客户的令牌中发布机密信息(比如说用户密码等等)。
在Python中创建JWT令牌的示例函数:
def create_token(user):"""Create a JWT token, set expiry, iat, etc"""payload = {'sub': user.id,'name': user.first_name,'role_id': user.role_id,'iat': datetime.utcnow(),'exp': datetime.utcnow() + timedelta(days=1)}token = jwt.encode(payload, MY_SECRET_KEY_SHHH_DONT_TELL_ANYONE, algorithm='HS256')return token.decode('unicode_escape')
上面的键sub,iat和exp跟随保留的JWT键,但我也添加了用户的名称和role_id。你将需要一个库来编码/解码JWT令牌。 JWT.io列出了许多语言的库。
链接
Introduction to JSON web tokens
JWT Debugger
OAuth
OAuth是一种认证协议,允许用户对没有密码的服务器执行认证。 OAuth存在很多版本 - OAuth 1.0,OAuth 1.0a和OAuth 2.0。
如果您曾使用Twitter,Google或Facebook帐户登录了某项服务,那么您已使用OAuth。
、
OAuth提供商(Facebook,Google等)通过提供您的服务(“OAuth客户端”)身份验证方式的私有,唯一的访问令牌,允许登录。
如果您要使用OAuth让用户登录您的服务,则需要将您的服务器注册为OAuth客户端。这通常会设置一个客户端ID和客户端密钥。登录到您的服务的用户将重定位到OAuth提供程序,用户可以在其中确认他们确实想要“登录”(即允许他们登录的服务器)访问OAuth提供程序的任何必需的信息。 )在我们的朋友Beorn的情况下...
在我们的朋友Beorn的情况下...
Beorn去http://knittingworld.com 买东西。
Beorn决定使用他的Google帐户登录。
提示Beorn输入他的google帐户信息(如果他还没有登录
输入信息后,Google(或者其它的OAuth提供商)将提示他是否要使用他的Google帐户登录http://knittinggworld.com 。
接受后,Beorn被重定向到http://knittingworld.com 。
如果knittingworld需要访问关于Beorn信息的资源,它可以向资源服务器(通过OAuth提供者)请求访问它们,只要它的token是有效的。
OWASP说:
建议使用OAuth 1.0a或OAuth 2.0,因为已发现第一个版本(OAuth1.0)容易受到session固定的影响。OAuth 2.0依靠HTTPS进行安全保障,目前OAuth的API(如Facebook,Google,Twitter和Microsoft)已经实现了。 OAuth1.0a很难使用,因为它需要使用用于数字签名的加密库。然而,由于OAuth1.0a不依赖HTTPS来实现安全性,因此它更适合于更高风险的事务。
链接
A Fun explanation of OAuth involving Donuts
OpenId
OpenId是另一种不需要密码的身份验证协议(类似于OAuth)。 OpenId网站有一个非常简洁明了的描述,在我看来:
OpenID允许您使用现有帐户登录多个网站,而无需创建新密码。您可以选择将信息与您的OpenID相关联,以便与您访问的网站(例如姓名或电子邮件地址)共享。使用OpenID,您可以控制与您访问的网站共享的信息量。使用OpenID,您的密码仅提供给您的身份提供商,然后该提供商会确认您访问的网站的身份。除了您的提供商,没有网站曾经看到您的密码,因此您不需要担心一个不道德或不安全的网站危害您的身份。
虽然从2005年开始,最近(2014年-h),OpenId发布了OpenId Connect,这是一种“基于OAuth 2.0系列规范的可互操作身份验证协议”(源)
OpenId和OAuth有什么区别?
OpenId类似于OAuth,但有一些差异。类似地,OpenId依赖于与第三方(依赖方(您登录的站点))交互以提供认证凭证的身份提供商。
不同的是,您可以使用OAuth允许您登录的网站能够访问来自提供程序的数据。这听起来可怕和混乱,但这里有一个简单的例子:
Beorn注册为twitter。他要推销他编织的帽子
Beorn不知道follow谁,没有人follow他。 Beorn悲伤的感觉不重要。
Twitter提示Beorn使用OAuth连接他的Google帐户,以便他可以导入他的联系人到Twiiter。
Beorn follow了一群人,包括来自他多年没有见过的高中的老朋友
Beorn这样做了,现在他正在不停地tweeting。
链接
What is OpenId?
OpenId Connect FAQ
OpenId Connect Video
What's the differene between OpenId vs OAuth?
What's the differene between OpenId vs OAuth? (different thread)
OpenId according to Dave -- I like this one, albeit dated
这里是Stack Overflow的登录页面的图片,它提供了许多不同的身份验证方法:
资源和脚注
1 - Dos and Don’ts of Client Authentication on the Web. Page 2.
2 - Dos and Don’ts of Client Authentication on the Web. Page 1.
http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication
https://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/
https://pdos.csail.mit.edu/papers/webauth:sec10.pdf
OWASP Authentication Cheat Sheet