App开放接口api安全性的设计与实现
Posted on 2016-09-29 11:49 琪齐 阅读(4121) 评论(0) 编辑 收藏html
阅读目录python
回到目录web
前言
在app开放接口api的设计中,避免不了的就是安全性问题,由于大多数接口涉及到用户的我的信息以及一些敏感的数据,因此对这些接口须要进行身份的认证,后端
那么这就须要用户提供一些信息,好比用户名密码等,可是为了安全起见让用户暴露的明文密码次数越少越好,咱们通常在web项目中,大多数采用保存的session中,api
而后在存一份到cookie中,来保持用户的回话有效性。可是在app提供的开放接口中,后端服务器在用户登陆后如何去验证和维护用户的登录有效性呢?缓存
回到目录安全
设计
对于敏感的api接口,需使用https协议服务器
https是在http超文本传输协议加入SSL层,它在网络间通讯是加密的,因此须要加密证书。https协议须要ca证书,通常须要交费。cookie
回到目录网络
一、原理
用户登陆后向服务器提供用户认证信息(如帐户和密码),服务器认证完后给客户端返回一个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
就变成一个动态的并且相对的具备高安全的,保证数据安全的访问。
二、具体实现
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(
'|'
)
# 得到数据,以“|”分割开
(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
(url)
ret
=
requests.get(url)
(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'
)
(ret.text)
这是比较粗超的API认证机制,能够初步了解。