我正在尝试使用Ruby on Rails构建Web服务。用户通过HTTP Basic Auth进行身份验证。我想在用户名和密码中允许任何有效的UTF-8字符。
问题是浏览器在将它们发送到我的服务之前会破坏Basic Auth凭证中的字符。为了测试,我使用'カタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナ'作为我的用户名(不知道这意味着什么 - AFAIK它是我们的QA家伙想出的一些随机字符 - 请原谅我,如果它有点冒犯)。< / p>
如果我把它看作一个字符串和做username.unpack(“H *”)将其转换为十六进制,我得到:“3e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a8”这似乎大约为右32个汉字字符(每/ 6个十六进制数字3个字节)
如果我使用通过HTTP Basic身份验证进入的用户名执行相同的操作,我会得到: 'bafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaac'。它显然要短得多。使用Firefox Live HTTP Headers插件,这是发送的实际标头:
Authorization: Basic q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o6q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o=
看起来像'bafbba ...'字符串,交换了高低字节(至少当我将其粘贴到Emacs中时,基本64解码,然后切换到hexl模式)。这可能是用户名的UTF16表示形式,但我没有任何东西可以将其显示为除了胡言乱语之外的任何内容。
Rails正在将内容类型标头设置为UTF-8,因此浏览器应该以该编码发送。我得到了表单提交的正确数据。
Firefox 3.0.8和IE 7都会出现问题。
所以...是否有一些魔术让网络浏览器通过HTTP Basic Auth发送UTF-8字符?我在接收端处理错误了吗? HTTP Basic Auth是否不适用于非ASCII字符?
答案 0 :(得分:53)
我想在用户名和密码中允许任何有效的UTF-8字符。
放弃所有希望。基本身份验证和Unicode不会混用。
在base64ing之前,如何将非ASCII字符编码为基本认证用户名:密码令牌,没有标准(*)。因此,每个浏览器都会做出不同的事情:
*:有些人将标准解释为:
但是这些提案都没有包含在base64编码的auth令牌中,并且HTTP规范中的RFC2047引用实际上根本不起作用,因为它可能使用的所有地方都明确禁止RFC2047本身的'原子上下文'规则,即使HTTP标头尊重RFC822系列的规则和扩展,它们也没有。
总结:呃。除了Opera以外,在标准或浏览器中修复这一点几乎没有希望。这只是推动人们远离HTTP基本身份验证的另一个因素,有利于非标准和不易访问的基于cookie的身份验证方案。很遗憾。
答案 1 :(得分:5)
一个众所周知的缺点是基本身份验证不支持非ISO-8859-1字符。
有些UAs使用UTF-8代替(Opera会想到),但是也没有互操作性。
据我所知,除了通过定义处理所有Unicode的新身份验证方案之外,没有办法解决这个问题。并部署它。
答案 2 :(得分:3)
HTTP摘要身份验证也不是解决此问题的方法。它遇到了同样的问题,即客户端无法告诉服务器它正在使用什么字符集,服务器无法正确地假设客户端使用了什么字符集。
答案 3 :(得分:0)
您是否使用curl
之类的内容进行了测试,以确保它不是Firefox问题? HTTP Auth RFC对ASCII与非ASCII无声,但它确实表示标头中传递的值是用冒号分隔的用户名和密码,我在Firefox的字符串中找不到冒号正在报告发送。
答案 4 :(得分:0)
如果您要为Windows 8.1编码,请注意HttpCredentialsHeaderValue
文档中的示例是(错误地)使用UTF-16编码。合理的解决方法是切换到UTF-8(因为CryptographicBuffer.ConvertStringToBinary
不支持ISO-8859-1)。
答案 5 :(得分:-1)
我可能是一个完全无知的人,但是当我在ajax调用中发送UTF8字符串作为标题时,我找到了这个问题。
我可以通过在发送它之前在Base64中编码字符串来解决我的问题。这意味着您可以使用一些简单的JS在提交之前将表单转换为base64,这样就可以将其转换回服务器端。
这个简单的工具允许我将utf8字符串发送为简单的ASCII。我发现感谢这个简单的句子:
base64(此编码旨在使二进制数据在通过非8位干净的传输层传输时继续存在)。 http://www.webtoolkit.info/javascript-base64.html
我希望这会有所帮助。试着回馈一下社区!