Cookie的應用與重送


#1

大概就是有人問我 cookie 的相關問題,類似 curb 這個 gem 如何完成 cookie 重送的動作

這邊可以看到更多相關詳細的資訊
http://en.wikipedia.org/wiki/HTTP_cookie

首先學理的解釋,一般發送封包有兩個名詞,request 是我們送去的封包,response 是 server 回傳的封包

request 的 cookie 在 header 內叫做 Cookie,沒初始值所以第一個封包通常都沒 cookie,而 response 希望 client 重送回來的 cookie 叫做 Set-Cookie ,裡面通常會包括額外多些的資訊,類似作用域 ( domain / path ) 和過期時間,把 response 的 header 印出來,會有類似這種格式

require 'curb'
url = 'https://www.hsbc.com.hk/1/2/chinese/hk/investments/mkt-info/fcy/rates'
response = Curl.get(url)
#response.body_str #raw body
puts response_header = source.head

#=> HTTP/1.1 200 OK
#=> Date: Sat, 14 Feb 2015 15:53:11 GMT
#=> ......
#=> Set-Cookie: JSESSIONID=0000RgLIAC-jYb_H1XMfDbpIaPy:16tugp8no; Path=/
#=> Set-Cookie: CAMToken=xyRXRWhc9ZUIWrdLvELXhg4Svpc=; Path=/; Secure
#=> Set-Cookie: JSESSIONID=0000RgLIAC-jYb_H1XMfDbpIaPy:16tugp8no; Path=/
#=> Set-Cookie: HKWSK=96785930.20420.0000; path=/

此時取到最前面的一個分號,類似使用

puts cookies = response_header.scan(/Set-Cookie: (.[^;]*;)/).flatten.uniq.sort.join(' ')
#=> CAMToken=xyRXRWhc9ZUIWrdLvELXhg4Svpc=; HKWSK=96785930.20420.0000; JSESSIONID=0000RgLIAC-jYb_H1XMfDbpIaPy:16tugp8no;

之後再把這串連同 request 中的cookie一起送出即可,類似

response = Curl.get(url) do |http|
  http.headers['Cookie'] = cookies
end
response.body_str #=> 已設定cookie的網頁

即為所求,當然也可以不用那麼累,類似上面的 cookie 直接去取 JavaScript 中的

document.cookie

就有整段包好好的 cookie 給你用,類似先用瀏覽器登入,然後去 JavaScript(console) 下拿自己的 cookie,然後餵給 header cookie 段,就能拿到已經登入的網頁了

而另外一方面,其實送圖片和其他類似 css / js 也有可能會有 set-cookie 的部分,所以可能會漏掉一些,沒有瀏覽器直接開的完整

至於 cookie 的過期是個很有趣的東西,這東西過份相信了瀏覽器本身(瀏覽器會自動把過期的 cookie 刪除),所以除非 session 在 server 端,或是把 timestamp 放在 cookie 內,不過鮮少人把 cookie 內塞 timestamp ,也就會變成寫機器人放入的 cookie 永遠都不會過期,基本上就可以一直用下去(某作品就是…嗯…到現在都沒換過…)

so~ 以上,應該有描述完 cookie 的來龍去脈才是,有興趣的話可以研究 http 的 request & response 的封包,如果一邊沒研究透的話,應該就會出現阻礙才是

最後 … 這個測試的網址(HSBC)本身是個很困難破解的東西,如果 linux 下應該很難得到 X"D,建議不要嘗試,原因是該網站不會主動轉送 ssl 的加密 protocol,屬於 linux 的 curl ( curb ) 的問題,另外一方面是對方網站的壞心眼,有興趣的可以去玩玩看,關鍵字是 cipher,而 OSX 的 curl 應該會很正常才是


#2
#=> CAMToken=xyRXRWhc9ZUIWrdLvELXhg4Svpc=; HKWSK=96785930.20420.0000; JSESSIONID=0000RgLIAC-jYb_H1XMfDbpIaPy:16tugp8no;

再請問一下 jc…

一般 cookie 不是只有一串?他這有四串??

但如果遇到有識別碼的問題時…(就人眼辨識的那種)…

他的羅輯如何使用?(人眼可以人工…)

e.g.

http://insprod.tii.org.tw/database/insurance-1/query.asp

這種要如何試 ?

cookies 每 refresh 一次時就會不同(假設 server 有這設定…)

謝謝


#3

hmm… Set-Cookie 通常有一大票,因為會指向不同的 domain 且不同的過期時間,還有一大票設定,所以會分開成很多行送過來,當然同 name 的話會被覆蓋,但此時 client 端送回的 Cookie 是此作用 domain 和沒有過期的 cookie,且因為就在這個 domain 且還沒過期,所以送回的是 merge 的 cookie 就是,anyway你可以抓 response 的 header 出來研究應該就會知道了

至於你說的東西叫 session 和 captcha,這東西是隔離的就是,大概就是

[Server] => abc123(session id) => [Client]
[Server : abc123 的 captcha = 999] => 999的圖 => [Client]
[Client] => captcha的解答是999,請驗證 => [Server...yep,是999,他是人類]

簡單的來說就是結果存在 server 端,需要反向驗證回去,很像傳簡訊的驗證碼之類的,答案是存在server,而你無法從 cookie 觀察到答案,否則就蠢到極致|||

至於每次 refresh 都不一樣…通常都在 captcha 的比對和逆算上(captcha 的答案可能存在 cookie內,但 cookie 的內容是奇怪的演算法製成,通常破解困難),不然就對方耍笨了,因為每次都 set-cookie 其實會增加 response header 也就是回傳時的封包量的,至於如果上面寫的是session_id之類的字眼,就不用破了,因為就是上面的那個 demo,答案是存在 server 端的 記憶體 / 檔案 / DB 內的


#4

所以依道理來說…

假設 cookies vs. captcha 是有配對關係…

是不是其實我們只要連上一次…(用 chrome的 console 來讀 document.cookies )…

捉到現在的 cookies + 現在的 captcha …

再把這數字塞到參數重送就可以…?

好像羅輯上這樣就行…是嗎…


#5

A…你還是不懂我的意思…

我給你一張牌叫做 A,然後另外一個本子寫 A 的 user_id = 123 , captcha = 999 , age = 18 , sex = 0
然後你把 A 丟回來,然後說 captcha = 999
然後我本子內的 A 的 captcha 註銷掉
然後你再把 A 丟回來,然後說 captcha = 999 << 一定把你擋掉…不是註銷掉了咪

這是 session 的概念,後面到底對應多少資料你不知道的啊,給你的只有一個叫做 A 的 key 而已,而非完整的一對一且只對一個 captcha 而已好唄,當然你的概念某些特殊情況是可以實現的,類似重複交易攻擊,但在 session 的概念內這樣是行不通的


#6

是我耍呆了…

才想起來…

假設一般 server 每連一次都會更新 session 的話…

我用 curb 再連時也沒有用…因為 server 會重新指定 session …

所以掌控權都是在 session 上… 我想 jc 應是指這意思吧…

我太執著用 cookie 去騙…(就是用 cookie + captcha 去搭…)
→這招應該對有經驗的 developer 是沒用的…

所以如果我是用 session + captcha 搭配來記錄…

就只要每一次連session_id上就配算一次…再連就另一個 session_id…

那 user 就基本上無法破 session+captcha 的方式來捉資料…

是這意思嗎?..

因為之前有看很多人demo爬資料都是用 cookie 去偽裝…(login時+captcha…)…
才會想說是不是 client 都用 cookie+captcha 去偽裝上次的登入…
這樣可以成功登入(填入表格+captcha)…並捉取資料…
那應該是該網站沒寫好(算是另一種的資安漏洞?)

以上的觀念可能還是有問題…就只好請 jc 大法官釋疑囉…
對 session 的理解就是資料記在 session 中(server-side)…
對 cookies 的理解就是寫資料在 client cookies 中…
但其安全性&實作上的方式了解並不深…(技術債…小的知道…)
只好請 jc 給個方向理解囉…

謝謝


#7

照理說 session 不會一直換的,你 po 的那個網站比較特別罷了,其餘如你所說,session 在 server 端( 除非用cookie session ),出去的只有一個 session id 而已,背後實作妳不會知道的

至於如果碰到這種網站,就真的只能一步一步來,類似從 login 開始,取得 Set-Cookie 段才會是正確的 session id / cookie 就是

至於 captcha 很難解,這是正常的,那也是使用這技術的原因不是咪?怕你寫機器人之類的,所以通常想辦法找弱點或是繞道,不會是正面挑戰 captcha 的

PS:某台鐵定票系統是 captcha,但有趣的是該 captcha 提供語音服務,然後丟給 google voice to text…((下略


#8

再續問一下…

像網頁 coding 的問題怎處理?

用 iconv ?

require ‘curb’

捉 big5 的…跑出來在 linux 下就會出現亂碼…

但… curb(curl)不支援轉換…

用 iconv 好像也轉不出來呢…

nokogiri 的轉檔好像就都用 utf-8…

這種轉檔搭配 crawler 有好用的 gem ?

有些建好像有內建的 encoding 設定可轉換…

curb 是有這 bug ? 還是要怎用才是對的?

謝謝


#9

hmm…此題點到為止,自己去查,String 內有 encoding / force_encoding / encode 這三個 methods 可以用,doc 內都有寫的,簡單的來說看編碼是啥,錯了就改,錯了分兩種,一個是原本是Big5你當作是UTF8,第二種是內容是Big5你想轉成UTF8,也就這樣而已,那三個 methods 就可以解決這全部的問題之類的


#10

謝謝 jc…

試的過程又有其它問題呢…

而且…

methods 可以丟一個 class 當輸入值哦?..

一直以為只有 block, proc 之類可以丟進去 methods 的參數…

這又是哪招?..


#11

… “UTF-8” 就好,所以是

"HELLO".force_encoding('UTF-8')

force_encoding : 改標頭only
encode : 改標頭加實際轉碼
encoding : 看目前編碼

所以以下

x = "喵喵喵"
x.encoding #=> #<Encoding:UTF-8> #目前為UTF-8
y = x.encode('BIG5') # 內文轉換,從UTF-8轉成Big5後丟給y,x不改變,除非用驚嘆號
x.encoding #=> #<Encoding:UTF-8>
y.encoding #=> #<Encoding:Big5>
y.force_encoding('UTF-8') #把Big5改標頭用UTF-8顯示,內文不轉換
y.encoding #=> #<Encoding:UTF-8>

至於丟進class…為啥不能丟,你想怎樣丟就可以怎樣丟,重點是你丟進去要做啥,而非能丟啥進去就是了,而它應該用在原型判斷而以就是