我试图编写一个iOS应用程序作为我个人前端到我的城市图书馆的网站。实际上,我希望我的应用程序无形地访问图书馆的网页,输入我的用户名和密码,然后发送HTTP请求以无形地浏览图书馆的网络界面以获取我的结帐项目列表,在到期日期附近续订物品等。
第一步是能够发送我的用户名和密码。我已将图书馆的登录页面剥离到以下内容:
<html>
<body>
<form action="http://brown.ent.sirsi.net/client/en_US/home/search/patronlogin.loginpageform/TRAINING" method="post">
<input name="t:ac" type="hidden" value="http:$002f$002fbrown.ent.sirsi.net"></input>
<input name="t:formdata" type="hidden" value="gFJQUIXDSUXVXoGv49wm3q8cIUQ=:H4sIAAAAAAAAAFvzloG1XJ5Btjg1sSg5Qz8gsaQoP88nPz0zzyorvrQ4tSgvMTe1uIjBNL8oXS+xIDE5I1WvJLEgtbikqNJULzm/KDUnM0kvKbE4Vc8xCSiYmFzilpmak6ISnFpSWqAaepj7oejxP0wMjD4M3Mn5eUDTc/yAJpYwCPlkJZYl6uck5qXrB5cUZealW1cUlDBwIWwlxlmOpDoroCg/ObW4OLg0KTezuDgzP+/wuhSTtG/zzjExMFQU4LSyILG4uDy/KKW4kKGOgQHsTJgQQT0gLazl0gySWFRlZKakpOYBPeKA1yPJ+bkF+XmpeSXFeh5gHZj+iGpXEK6Q3sGGEdQg6xlBQcsGsQyHS4pBJpWQ4hKw3SWYLpkZ/Ely65YWZyYGJh8GjuScTKBqT3AogFyWmpOaCxRAcRkHxPJ4AyQmABiJtLaZAgAA"></input>
Library Card #: <input name="j_username" value = "29878001234567" type="text"></input><br/>
PIN: <input name="j_password" value="1234" type="text"></input><br/>
<input name="hidden" value="SYMWS" type="hidden"></input>
<input type="submit"></input>
</form>
</body>
</html>
当我从硬盘中打开此HTML文件时,请输入我的真实图书馆卡号和PIN,然后提交表单,我成功登录到图书馆的系统。当我点击&#34;提交&#34;只有上面代码中的虚拟数字,我收到&#34;登录失败&#34;屏幕就像我应该的那样。
我试图在我的Swift代码中模仿如下:
func loginToLibrary() {
let request = NSMutableURLRequest(URL: NSURL(string: "http://brown.ent.sirsi.net/client/en_US/home/search/patronlogin.loginpageform/TRAINING")!)
request.HTTPMethod = "POST"
var postString = "t:ac=http:$002f$002fbrown.ent.sirsi.net"
postString += "&t:formdata=gFJQUIXDSUXVXoGv49wm3q8cIUQ=:H4sIAAAAAAAAAFvzloG1XJ5Btjg1sSg5Qz8gsaQoP88nPz0zzyorvrQ4tSgvMTe1uIjBNL8oXS+xIDE5I1WvJLEgtbikqNJULzm/KDUnM0kvKbE4Vc8xCSiYmFzilpmak6ISnFpSWqAaepj7oejxP0wMjD4M3Mn5eUDTc/yAJpYwCPlkJZYl6uck5qXrB5cUZealW1cUlDBwIWwlxlmOpDoroCg/ObW4OLg0KTezuDgzP+/wuhSTtG/zzjExMFQU4LSyILG4uDy/KKW4kKGOgQHsTJgQQT0gLazl0gySWFRlZKakpOYBPeKA1yPJ+bkF+XmpeSXFeh5gHZj+iGpXEK6Q3sGGEdQg6xlBQcsGsQyHS4pBJpWQ4hKw3SWYLpkZ/Ely65YWZyYGJh8GjuScTKBqT3AogFyWmpOaCxRAcRkHxPJ4AyQmABiJtLaZAgAA"
postString += "&j_username=29878001234567"
postString += "&j_password=1234"
postString += "&hidden=SYMWS"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("response to login attempt = \(responseString)")
}
task.resume()
}
但是,当我运行Swift代码时,以下内容将打印到控制台:
response to login attempt = Optional(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><link rel="shortcut icon" href="/client/assets/4.5.03/ctx/favicon.ico" type="image/vnd.mircrosoft.icon" id="favicon"/><title>Unexpected Error</title><link type="text/css" rel="stylesheet" href="/client/assets/4.5.03/core/default.css"/><meta content="Apache Tapestry Framework (version 5.3.7)" name="generator"/></head><body><div id="exception"><h1>Unexpected Error</h1><div class="pageheading">The system encountered an error while processing the following request:</div><div class="url">/en_US/home/search/patronlogin.loginpageform/TRAINING</div><h2>Error Summary</h2><div class="cause">java.io.IOException: Client data associated with the current request appears to have been tampered with (the HMAC signature does not match).</div><div class="timestamp">Wed May 25 22:51:42 CDT 2016</div></div></body></html>)
在浏览器中解释它是:
意外错误
任何人都可以帮我弄清楚我的Swift代码发送的POST请求与我的浏览器从上面的精简网页发送的POST请求有何不同?
如果我改变了t:formdata
输入的值,我可以从我的精简网页中获得与浏览器相同的错误(HMAC签名不匹配)。我已尝试将=
(t:formdata
值中约30个字符)的编码百分比编码为%3D
,甚至将/
编码为{ {1}},但这没有用。
答案 0 :(得分:1)
简答:你无法完成你正在尝试的事情。你需要做一些研究来解决HMAC问题。
长答案: HMAC(基于哈希的消息认证码)是应用于消息正文的散列函数以及密钥的产物。因此,不是通过Web服务请求发送用户名和密码,而是发送私钥和HMAC的一些标识符。当服务器收到请求时,它会查找用户的私钥并使用它为传入请求创建HMAC。如果随请求提交的HMAC与服务器计算的HMAC匹配,则认证请求。
有两大优点。第一个是HMAC允许您验证密码(或私钥),而无需用户将其嵌入请求中,第二个是HMAC还验证请求的基本完整性。如果攻击者以任何方式操纵请求,则签名将不匹配,并且请求将不会被验证。这是一个巨大的胜利,特别是如果Web服务请求不是通过安全的HTTP连接进行的。
请查看此link以获取有关HMAC的更多信息。
答案 1 :(得分:0)
您发布到symphony的数据缺少URL编码,我遇到了同样的问题。这就是为什么交响乐得到错误的原因:formdata