在Python中用Request庫模擬登陸(二):博客園(簡單加密,無驗證碼)

!已失效!

源代碼分析

博客園的登陸頁面很是簡單,查看網頁源代碼,能夠發現兩個輸入框的id分別爲input一、input2,複選框的id爲remember_me,登陸按鈕的id爲signin。html

還有一段JavaScript代碼,下面來簡單分析一下。python

先來看$(function(){});函數:jquery

1 $(function () {
2     $('#signin').bind('click', function () {
3         signin_go();
4     }).val('登 錄');
5 });

$(function(){});是$(document).ready(function(){})的簡寫。當頁面加載完成以後,$(function(){})裏的代碼就會被執行。git

$('#signin')表示選取id爲signin的元素,即登陸按鈕。github

bind()方法爲被選元素添加一個或多個事件處理程序,並規定事件發生時運行的函數。ajax

val()方法返回或設置被選元素的值。json

當點擊登陸按鈕時,將執行signnin_go()函數。瀏覽器

 

JSEncrypt是一個用於RSA加密的庫。在signnin_go()函數中,經過JSEncrypt對用戶名和密碼進行了加密,setPublicKey()函數裏面就是加密的公鑰。服務器

$('#remember_me').prop('checked')返回複選框的狀態,勾選時返回true,不然返回false。網絡

兩段加密後的密文和複選框的狀態被保存在一個名爲ajax_data的對象裏。代碼以下:

1 var encrypt = new JSEncrypt();
2 encrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB');
3 var encrypted_input1 = encrypt.encrypt($('#input1').val());
4 var encrypted_input2 = encrypt.encrypt($('#input2').val());
5 var ajax_data = {
6     input1: encrypted_input1,
7     input2: encrypted_input2,
8     remember: $('#remember_me').prop('checked')
9 };

 

而後就是最主要的$.ajax({})函數了,ajax()方法經過HTTP請求加載遠程數據,在不刷新頁面的狀況下與服務器交換數據,返回其建立的 XMLHttpRequest 對象。詳情請參考jQuery ajax - ajax() 方法

 1 $.ajax({
 2     url: ajax_url,
 3     type: 'post',
 4     data: JSON.stringify(ajax_data),
 5     contentType: 'application/json; charset=utf-8',
 6     dataType: 'json',
 7     headers: {'VerificationToken': '。。。省略,此處是一大串字符。。。'},
 8     success: function (data) {
 9         if (data.success) {
10             $('#tip_btn').html('登陸成功,正在重定向...');
11             location.href = return_url;
12         } else {}
13     },
14     error: function (xhr) {}
15 });

上面的代碼中作了一些省略。須要特別注意的是headers屬性,刷新以後,VerificationToken的值將會改變,因此在模擬登陸時,必須先獲取這一段字符串。登陸成功後,頁面將進行跳轉。

 

抓包分析

這是登陸時的POST請求,其中有3個參數要特別注意:

VerificationToken就是上文中提到的一段變化的字符串。

Ajax異步請求比傳統的同步請求多了一個頭參數,即X-Requested-With。

Content-Type用於定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什麼形式、什麼編碼讀取這個文件,這就是常常看到一些Asp網頁點擊的結果倒是下載到的一個文件或一張圖片的緣由。在這裏返回的是json格式的數據。當輸入錯誤的用戶名和密碼時,將獲得下面的json數據:

正確的用戶名和密碼將獲得{"success":true}

 

模擬登陸

 1 import requests
 2 import json
 3 login_url='https://passport.cnblogs.com/user/signin'
 4 return_url='https://home.cnblogs.com/u/-E6-/'#個人主頁
 5 session=requests.session()
 6 
 7 #獲取VerificationToken
 8 login_page=session.get(login_url)
 9 p=login_page.text.find('VerificationToken')+len('VerificationToken')+4
10 token=login_page.text[p:login_page.text.find("'",p)]
11 
12 headers={'Content-Type': 'application/json; charset=UTF-8',
13           'X-Requested-With': 'XMLHttpRequest',
14           'VerificationToken':token}
15 session.headers.update(headers)
16 #能夠經過抓包獲取加密後的用戶名和密碼,我將在附錄部分介紹如何在Python中加密
17 data={"input1":"。。。省略。。。",
18       "input2":"。。。省略。。。",
19       "remember":True}
20 
21 #模擬登陸
22 response=session.post(login_url,data=json.dumps(data))
23 print(response.text)
24 #{"success":true}
25 #登陸成功
26 
27 #跳轉到主頁
28 home_page=session.get(return_url)
29 #獲取主頁標題
30 p=home_page.text.find('<title>')+len('<title>')
31 title=home_page.text[p:home_page.text.find('</title>',p)]
32 print(title)
33 #E6的主頁 - 博客園
34 #若是登陸失敗,跳轉到主頁時返回的結果沒有title標籤,home_page.text將爲'須要登錄'

 

附錄:在Python中進行RSA加密

在python中加密須要Crypto和base64

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from base64 import b64encode

在網頁源代碼中能夠直接找到公鑰(位於setPublicKey()函數裏):MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB

標準的公鑰格式爲

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNPaXE9SARgvD7l5FgU5B/ibE/
Uuu4okbt6LGzXVYtx1tzgdnV9/BiDgauRsWGjofo0o3+cVLs16hUdRJ9BoAr0jL8
00AKy9rkcOi0lJI8XBZrtX2Ad+uwf4kLNjL2MkLkSbhtwRzpiAFcjMrhyOi6y/0c
KafXI3SXOgVBA5w2dQIDAQAB
-----END PUBLIC KEY-----

每行64個字符。

 

 

 1 #標準的公鑰格式,bytes類型,每64字符換一次行
 2 key_bytes=b"-----BEGIN PUBLIC KEY-----\n\
 3 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0M\n\
 4 cc\uMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbd\n\
 5 gOQT6CuFQBMjbyGYv\lVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prk\n\
 6 nrScAKC0XhadTHT3Al0QIDAQAB\n\
 7 -----END PUBLIC KEY-----"
 8 #生成Crypto.PublicKey.RSA._RSAobj類型的對象
 9 publickey=RSA.importKey(key_bytes)
10 #構造「加密器」
11 encryptor=PKCS1_v1_5.new(publickey)
12 #加密的內容必須爲bytes類型
13 username=b'123'
14 password=b'abc'
15 #加密,並將結果轉換成字符串
16 input1=str(b64encode(encryptor.encrypt(username)),'utf-8')
17 input2=str(b64encode(encryptor.encrypt(password)),'utf-8')
18 
19 data={'input1':input1,'input2':input2,'remember':True}
相關文章
相關標籤/搜索