验证HTTP请求的来源
我有两个系统需要互相通信。它们的设置如下:
系统 A
,在 Google App Engine (GAE) 上运行 Django (Python 2.5)
系统 B
,在 Ubuntu/Linux 上运行 Django (Python 2.6),使用 Lighttpd(可能以后会用 nginx)
系统 A 会定期向系统 B 发出请求(我们称之为“请求”),使用 Url Fetch。
系统 B 有一个 Django 应用程序,设置为监听这些请求,使用一个类似于 urls.py
的文件:
urlpatterns = patterns('producer.views',
url(r'^requisition$', 'requisition', name='requisition'),
)
还有一个对应的 views.py
文件,内容类似于:
import json
from django.http import HttpResponse
def requisition(request):
" do something "
response = HttpResponse()
response['Content-type'] = 'application/json'
response.write(json.dumps(...))
return response
如果系统 B 只对来自系统 A 的请求做出响应,这将对系统的安全性有很大帮助。
我想知道系统 B 有哪些方法可以验证请求确实来自系统 A。我考虑过以下几种方案:
- 检查 IP 地址是否来自 GAE(不过我不知道 GAE 的 IP 地址,可能会变化,也可能会被伪造)
- 检查 IP 的反向 DNS 是否来自 GAE(但我不知道 GAE 的 DNS 记录是什么,是否会变化,也可能被伪造)
- 使用来自系统 A 的 TLS 客户端证书 - 但我不知道如何在 GAE 上做到这一点
- 基于共享的内容(比如盐值)进行挑战/响应,使用 pycrypto
理想情况下,我希望最终能得到一个类似于 views.py
的文件:
...
from django.http import HttpResponseForbidden
def requisition(request):
" do something "
if not verify_request_origin():
return HttpResponseForbidden("Denied.")
response = HttpResponse()
...
其中 verify_request_origin() 函数在请求来自 GAE 上的 系统 A
时返回 true。
谢谢,我期待听到你的想法。
4 个回答
系统A可以通过urlfetch.fetch发送HTTPS请求,只需要确保URL参数以https://
开头。不过,这样做并不能让系统B确认请求的身份(虽然可以防止数据被窃听和中间人攻击);也无法使用客户端TLS证书。
想要验证请求确实来自GAE(这其实是可行的:只需使用谷歌自己的DNS服务器8.8.8.8——如果有人能攻破谷歌的DNS,那么他们想要欺骗你的系统B就不是最严重的问题了;-))也没有帮助,原因是一样的:这可能是任何GAE应用(它们共享一堆IP地址,而某个IP地址在短时间内可能被多个GAE应用使用)。
因此,在GAE的限制下,用共享密钥加密数据包似乎是最简单的办法。可以考虑使用PyCrypto——也许在前面加上exPyCrypto会更好;或者,你也可以试试SlowAES(我对后者特别偏爱,当然;-)。
听起来只要在链接上使用SSL,并在查询字符串中加入一个密码就可以了。
SSL可以防止别人偷看你的数据,而且你不会把查询信息暴露给你控制之外的系统,所以用一个共享的秘密就足够了(而且比通过IP地址来追踪更安全,因为其他GAE网站也会使用这些地址)。