App開放接口api安全性的設計與實現


前言

在app開放接口api的設計中,避免不了的就是安全性問題,因為大多數接口涉及到用戶的個人信息以及一些敏感的數據,所以對這些接口需要進行身份的認證,

那么這就需要用戶提供一些信息,比如用戶名密碼等,但是為了安全起見讓用戶暴露的明文密碼次數越少越好,我們一般在web項目中,大多數采用保存的session中,

然后在存一份到cookie中,來保持用戶的回話有效性。但是在app提供的開放接口中,后端服務器在用戶登錄后如何去驗證和維護用戶的登陸有效性呢?

設計

對於敏感的api接口,需使用https協議

https是在http超文本傳輸協議加入SSL層,它在網絡間通信是加密的,所以需要加密證書。https協議需要ca證書,一般需要交費。

  1、原理

用戶登錄后向服務器提供用戶認證信息(如賬戶和密碼),服務器認證完后給客戶端返回一個PID令牌,用戶再次獲取信息時,

帶上此令牌,如果令牌正取,則返回數據。對於獲取Token信息后,訪問用戶相關接口,客戶端請求的url需要帶上如下參數:

  ① 時間戳:timestamp
  ② PID令牌:PID(在這我們給定義為PID)

 

然后將所有用戶請求的參數(包括timestamp,pid),然后更具MD5加密(可以加點鹽),生成動態的url。

然后登陸后每次調用用戶信息時,帶上timestamp,pid參數。

加上時間戳和pid后的URL:http://127.0.0.1:8888/index?pid=d073dae99f70b0cda2fa1ef8d25c527f|1475117419.5424652|0

就變成一個動態的而且相對的具有高安全的,保證數據安全的訪問。

  2、具體實現

1. api請求客戶端想服務器端一次發送用用戶認證信息(用戶名和密碼),服務器端請求到改請求后,驗證用戶信息是否正確。
  如果正確:則返回一個唯一不重復的字符串,然后在Redis(任意緩存服務器)中維護這個用戶信息關系,以便其他api對pid的校驗。
  如果錯誤:則返回錯誤碼。

2.服務器設計一個url請求攔截規則

  ①判斷是否包含timestamp,pid參數,如果不含有返回錯誤碼。

  ②根據用戶請求的url參數,服務器端按照同樣的規則生成動態的URL,對比請求的動態url與服務端生成的是否相等,相等則放行允許訪問。

  ③判斷服務器接到請求的時間和參數中的時間戳是否相差很長一段時間(時間自定義如十秒),如果超過則說明該url已經過期。

  ④記錄下每次請求的動態URL,規定一個動態的URL只能訪問一次,檢測每次請求的url是否請求過,去過存在就返回錯誤代碼(處理url被攔截並且在十秒內請求的訪問)。

  ⑤此url攔截只需對獲取身份認證的url放行(如登陸url),剩余所有的url都需攔截。

3.定期處理保存下來的動態請求URL

代碼實現

服務端規定的規則

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import hashlib
import time

access_record = []  # 創建第一次登錄過URL列表

PID_LIST = [  # pid列表
    'qwe',
    'ioui',
    '234s',
]


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # 獲取url中全部數據
        pid = self.get_argument('pid', None)
        # 獲取變量
        m5, client_time, i = pid.split('|')  # 獲得數據,以“|”分割開
        print(m5, client_time, i)
        server_time = time.time()  # 服務端的當前時間
        # 時間超過10s禁止
        if server_time > float(client_time) + 10:  # 服務端的當前時間大於客戶端當前時間加10秒,表示過期不允許訪問
            self.write('gun')
            return
        # 處理10s內容重復的請求
        if pid in access_record:  # 如果客戶端請求的動態URL在第一次登錄過的URL列表中
            self.write('gun')
            return
        access_record.append(pid)  # 允許通過的url添加到列表中

        pid = PID_LIST[int(i)]  # 獲得客戶端發來的pid后面攜帶的數字
        ramdom_str = "%s|%s" % (pid, client_time)  # 把客戶的pid與當前時間戳拼接
        h = hashlib.md5()  # MD5加密值
        h.update(bytes(ramdom_str, encoding='utf-8'))  # 把客戶的pid與當前時間戳拼接一個字符串再盡心md5加密
        server_m5 = h.hexdigest()  # 服務端生成的動態URL
        # print(m5,server_m5)
        if m5 == server_m5:  # 客戶生成的與服務端生成的進行對比
            self.write("Hello, world")
        else:
            self.write('gun')

application = tornado.web.Application([
    (r"/index", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

客戶端按規則生成符合的

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
import requests
import hashlib

PID = 'qwe'  # 客戶的PID

current_time = time.time()  # 當前時間戳
ramdom_str = "%s|%s" % (PID, current_time)  # 把pid與當前時間戳拼接成一個字符串
h = hashlib.md5()  # md5加密
h.update(bytes(ramdom_str, encoding='utf-8'))  # 把pid與當前時間戳拼接成一個字符串再進行md5加密
UID = h.hexdigest()  # 加密后的字符串

q = "%s|%s|0" % (UID, current_time)  # 在把這個字符串后面拼接一個數值 0
url = 'http://127.0.0.1:8888/index?pid=%s' % q  # 生成最后生成的動態url
print(url)
ret = requests.get(url)
print(ret.text)

測試效果代碼

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests

ret = requests.get('http://127.0.0.1:8888/index?pid=c2539948caa7b7fe0d00fcd9d75b7574|1474341577.4938722|0')
print(ret.text)

這是比較粗超的API認證機制,可以初步了解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM