REST API 安全设计指南

本文陈述的是怎么为您的PHP项目落实谷歌的Oauth系统。那些示例PHP脚本非常的慢,对扩充你的PHP项目登记当然是很有接济的。

用Python的Django框架编写从谷歌 Adsense中获取报表的接收,djangoadsense

 笔者成功了翻新大家在
Neutron的实时入账总结。在自己花了七日的时辰成功同期更新了我们的PHP脚本之后,小编最后认决定初始选用Python实行抓取,那是值得自个儿去开销小编的日子和生机的事务。笔者创建了一个Django程序,它能够从不一样的来自存款和储蓄收入总括,小编可以用那么些去简历视图和用来总计工具的API。

因而在过去的几天里,作者写了二个剧本,它能够登陆到任何的网页并抓取数据,也许,假若这一个网页有
API,能够平昔访谈 API。笔者开采了一些事情。

1.requests >httplib2(requests多于httplib2);

2.SOAP很不好,但它起码是一个API,Suds使SOAP好一点。作者明白到SOAP是自家说知道的API中,唯生龙活虎三个截然基于.net开荒的。

3.Beautiful Soup是一个很好的呼救对象;

4.小编实在特别欣喜,这么多厂家能在这里么倒霉的才干中生活下去。
 

自家挽回了 GoogleAdsense,他们将会持有最佳的API,並且为此变成最简便的贯彻。他有着比自个儿预想的要多的挑衅。分明你不恐怕单独插入顾客名/密码或是APIkey去获得获得步向API的入口,你必得实现全数Oauth2的拉手流程。

噩运的是,小编意识文书档案不比自身期望过得那么轻巧查询。小编开采了重重死链接。小编感觉,在这里上边谷歌(Google卡塔尔(قطر‎的人相应做的更加好。比方,在她们的up
to date developer docs文档中,作者开掘他们建议了broken link to read more
about authentication and
authorization。(好的,多么古怪,小编快速提交了这一个标题,这几个链接终于开头职业了,小编猜你会多谢笔者。)

据此,那篇博客将尝试记录从Adsense获取报表到自个儿的Django应用的进度。

为了采纳Google的API来访谈Adsense报表,你须求接受Adsense Management API.
这些API只提供OAuth,所以您必要在浏览器中起码完成叁遍证实进程,来获得你的证件,然后你能够保存那几个表明来张开下一步操作。说真的,小编生机勃勃度据书上说过OAuth很频仍了,可是直到以后,作者在试行中仍尚未索要来行使它。所以本身是边做边学,并应接咱们留言建议本人说的失常之处。

就本人所知,谷歌对于它的各样产物都装有一个小幅度的API。在研讨Adsense早先,你须求在GoogleAPI
调整台注册你的使用。作者已经成功注册了自家的应用。因为本身还不曾叁个可用的UEscortL地址,小编后天临时使用作者的花销UOdysseyL(localhost:8000)。它运作起来如同符合规律。并行使提供的这几个链接下载JSON文件。

还应该有,当你管理你的APIs的时候,你要求张开服务选项卡,张开AdSense
Management
API选项。不然,当您品尝发送诉求的时候,你会得到一个乖谬音讯“Access Not
Configured”。

谷歌已经创建了一个Python
客商端库,你能够自由的经过pip来设置那么些库。它还富含多少个Django样例项目,这些项目采取那个库完毕OAuth2的握手进程。小编想,它是接收Django
1.1编写制定的(因为在写那么些类其他时候,Django
1.5才正好发布),所以它可能有一点点过时,可是它但是一个好的开首点。

自家的运用很简短。笔者只要求读取钦命日期的纯收入金额,并保留到自己的地点数据库。

自个儿在djaongo项目中开创了多少个新的施用,叫做“adsense”。并创造了叁个models.py文件来囤积认证证书。
 

from django.contrib.auth.models import User
from django.db import models
from oauth2client.django_orm import CredentialsField

class Credential(models.Model):
  id = models.ForeignKey(User, primary_key=True)
  credential = CredentialsField()

class Revenue(models.Model):
  date = models.DateField(unique=True)
  revenue = models.DecimalField(max_digits=7, decimal_places=2)

  def __unicode__(self):
    return '{0} ${1}'.format(self.date, self.revenue)

本人把从API调节台下载的JSON文件放到本人的选取的公文夹下边,并创制了一个views.py文件

 

import os

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import Site
from django.http import HttpResponseBadRequest, HttpResponse
from django.http import HttpResponseRedirect
from oauth2client import xsrfutil
from oauth2client.client import flow_from_clientsecrets
from oauth2client.django_orm import Storage

from .models import Credential

CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secrets.json')

FLOW = flow_from_clientsecrets(
  CLIENT_SECRETS,
  scope='https://www.googleapis.com/auth/adsense.readonly',
  redirect_uri='http://{0}/adsense/oauth2callback/'.format(
    Site.objects.get_current().domain))

@login_required
def index(request):
  storage = Storage(Credential, 'id', request.user, 'credential')
  credential = storage.get()
  if credential is None or credential.invalid is True:
    FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY,
                            request.user)
    authorize_url = FLOW.step1_get_authorize_url()
    return HttpResponseRedirect(authorize_url)
  else:
    return HttpResponse('Already validated.')

@login_required
def auth_return(request):
  if not xsrfutil.validate_token(settings.SECRET_KEY,
                  request.REQUEST['state'], request.user):
    return HttpResponseBadRequest()
  credential = FLOW.step2_exchange(request.REQUEST)
  storage = Storage(Credential, 'id', request.user, 'credential')
  storage.put(credential)
  return HttpResponseRedirect("/")

在 urls.py 文件中本人蕴涵了多少个链接指向自家的应用的url文件

main urls.py:

from django.conf.urls import patterns, include, url
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns(
  '',
  url(r'^adsense/', include('adsense.urls', namespace='adsense')),

  url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
  url(r'^admin/', include(admin.site.urls)),
)

adsense/urls.py:

from django.conf.urls import patterns, url

urlpatterns = patterns(
  'adsense.views',
  url(r'^$', 'index', name='index'),
  url(r'^oauth2callback/$', 'auth_return', name='auth_return'),
)

最后,创造了三个经过给定日期调用API并收获收入的类。它献身adsense/tasks.py,因为本身计划把它看成职务,钩在
Celery/ RabbitMQ之上。奥门新浦京官方网站,
 

import datetime
import httplib2

from apiclient.discovery import build
from django.contrib.auth.models import User
from oauth2client.django_orm import Storage

from .models import Credential, Revenue

TODAY = datetime.date.today()
YESTERDAY = TODAY - datetime.timedelta(days=1)

class Scraper(object):
  def get_report(self, start_date=YESTERDAY, end_date=TODAY):
    user = User.objects.get(pk=1)
    storage = Storage(Credential, 'id', user, 'credential')
    credential = storage.get()
    if not credential is None or credential.invalid is False:
      http = httplib2.Http()
      http = credential.authorize(http)
      service = build('adsense', 'v1.2', http=http)
      reports = service.reports()
      report = reports.generate(
        startDate=start_date.strftime('%Y-%m-%d'),
        endDate=end_date.strftime('%Y-%m-%d'),
        dimension='DATE',
        metric='EARNINGS',
      )
      data = report.execute()
      for row in data['rows']:
        date = row[0]
        revenue = row[1]

        record = Revenue()
        try:
          r = Revenue.objects.get(date=date)
          pk = r.id
        except Revenue.DoesNotExist:
          pk = None
        record.id = pk
        record.date = date
        record.revenue = revenue
        record.save()

为了让它能干活起来,小编在浏览器展开
get_report(卡塔尔国 方法。祝贺笔者啊!。它能顺遂专门的学问了。

Adsense中收获报表的施用,djangoadsense 我达成了翻新大家在
Neutron的实时入账计算。在本人花了二十一日的小运成功并…

REST API 安全陈设指南。REST的齐全部都是REpresentational State
Transfer,它使用守旧Web特点,建议提议三个既适应客商端应用又适应服务端的接纳的、统黄金时代构造,相当大程度上统大器晚成及简化了网址结构划虚构计。

在这里早前,大家早就覆盖了含蓄推特(TWTR.US卡塔尔、推特(TWTR.US卡塔尔(قطر‎、谷歌plus以至推特(Twitter卡塔尔国的Oauth登陆系统示范。非常不满在此之前本身疏漏掉了Google的Oauth登入系统。后天我们就来看一下什么样为你的web项目贯彻Google的Oauth系统。

近来在二种主流的Web服务达成方案中,REST方式服务比较复杂的SOAP和XML-RPC对比来说,特别简洁,越多的web服务起首应用REST设计并落到实处。但其紧缺安全特点,《REST
API 安全布署指南》正是三个REST
API安全规划的指南,权当投砾引珠,推荐网站后台设计及网址布局师们阅读。

在自此边,大家曾经覆盖了含有推特(Twitter卡塔尔国(TWTPAJERO.US卡塔尔、Twitter、Googleplus以至脸书的Oauth登入系统示范。很可惜以前笔者脱漏掉了谷歌的Oauth登入系统。后天大家就来看一下哪些为您的web项目达成Google的Oauth系统。这些示例脚本异常的快,对扩展你的web项目登记当然是很有帮扶的。

作品目录

奥门新浦京官方网站 1

  • 1,REST API
    简介
  • 2,身份认证
    • 2.1 HTTP
      Basic
    • 2.2 API
      KEY
    • 2.3
      Oauth1.0a或者Oauth2
    • 2.4
      JWT
  • 3 授权
  • 4 URL过滤
  • 5
    主要功效加密传输
  • 6 速率约束
  • 7 错误管理
  • 8
    关键ID不透明处理
  • 9 其余注意事项

Google Oauth登入系统开拓示范

1,REST API 简介

REST的齐全部都以REpresentational State
Transfer,表示表述性无状态传输,没有须要session,所以每趟诉求都得带上半身份ID明音讯。rest是依照http公约的,也是无状态的。只是一种构造格局,所以它的石嘴山特点都需我们本身完结,未有现有的。建议具备的必要都因此https合同发送。RESTful
web services 概念的基本正是“能源”。 能源得以用 U奥迪Q3I 来代表。客商端采纳HTTP 左券定义的主意来发送央求到这个U牧马人Is,当然恐怕会以致这个被访问的”财富“状态的改进。HTTP诉求对应提到如下:

========== ===================== ========================HTTP 方法 行为 示例========== ===================== ========================GET 获取资源的信息 http://xx.com/api/ordersGET 获取某个特定资源的信息 http://xx.com/api/orders/123POST 创建新资源 http://xx.com/api/ordersPUT 更新资源 http://xx.com/api/orders/123DELETE 删除资源 http://xx.com/api/orders/123========== ====================== =======================
对于央求的多寡貌似用json可能xml情势来代表,推荐应用json。

数据库设计

2,身份认证

身份认证包括很三种,有HTTP Basic,HTTP Digest,API
KEY,Oauth,JWK等格局,上面轻松解说下:

数据库设计相当粗略,如下所示:

2.1 HTTP Basic

REST由于是无状态的传导,所以每贰回号召都得带上半身份验证新闻,身份验证的点子,身份认证的主意有许二种,第意气风发种就是http
basic,这种艺术在顾客端要求简短,在服务端落成也超级轻易,只需容易安排apache等web服务器就可以兑现,所以对于简易的劳动来说依旧挺方便的。不过这种艺术安全性异常低,就是简单的将客商名和密码base64编码放到header中。
base64编码前:Basic admin:adminbase64编码后:Basic YWRtaW46YWRtaW4=放到Header中:Authorization: Basic YWRtaW46YWRtaW4=
正是因为是大致的base64编码存款和储蓄,切记切记在这里种方法下一定得精心使用ssl,不然就是裸奔了。
在一些付加物中也是依赖那体系似方式,只是未有采纳apache的basic机制,而是本人写了验证框架,原理还是相似的,在一回呼吁中base64解码Authorization字段,再和表达新闻做校验。很天下有名这种艺术不通常,认证新闻一定于公然传输,其它也未曾防暴力破解功用。

CREATE TABLE users  
(  
id INT PRIMARY KEY AUTO_INCREMENT,  
email VARCHAR(50) UNIQUE,  
fullname VARCHAR(100),  
firstname VARCHAR(50),  
lastname VARCHAR(50),  
google_id VARCHAR(50),  
gender VARCHAR(10),  
dob VARCHAR(15),  
profile_image TEXT,  
gpluslink TEXT
2.2 API KEY

API Key正是透过客户居民身份表明之后服务端给顾客端分配三个API
Key,相仿:
二个粗略的统筹示例如下: client端:

奥门新浦京官方网站 2

 

client端向服务端注册,服务端给客商端发送响应的api_key以及security_key,注意保存不要走漏,然后顾客端根据api_key,secrity_key,timestrap,rest_uri选择hmacsha256算法获得叁个hash值sign,布局途中的url发送给服务端。
服务端收到该诉求后,首先验证api_key,是否留存,存在则收获该api_key的security_key,接着验证timestrap是不是超越时间约束,可依照系统成而定,那样就幸免了有的重播攻击,途中的rest_api是从url获取的为/rest/v1/interface/eth0,末了总计sign值,完以往和url中的sign值做校验。那样的宏图就幸免了数码被曲解。
通过这种API
Key的布置方法加了岁月戳防止了蓬蓬勃勃部分回放,加了校验,幸免了数据被曲解,相同的时候防止了传输顾客名和密码,当然了也是有自然的支出。

1,域名注册

2.3 Oauth1.0a或者Oauth2

OAuth和煦适用于为外界应用授权访谈本站能源的境况。当中的加密机制与HTTP
Digest身份认证相比较,安全性越来越高。使用和布局都比较复杂,这里就不关乎了。

在这里挂号大概加多你的域名。

2.4 JWT

JWT 是JSON Web
Token,用于发送可经过数字签字和表达的事物,它包涵二个连贯的,UTiguanL安全的JSON对象,服务端可通过深入分析该值来注脚是还是不是有操作权限,是还是不是过期等安全性检查。由于其紧密的特色,可放在url中要么
HTTP Authorization头中,具体的算法就好像下图

奥门新浦京官方网站 3

 

奥门新浦京官方网站 4

3 授权

身份ID明之后正是授权,依据差异的身份,授予分歧的拜见权限。比如admin客户,普通客户,auditor用户都以分裂的地方。简单的亲自去做:
php$roles = array('ADMIN'=>array('permit'=>array('/^((/system/(clouds|device)$/'), // 允许访问哪些URL的正则表达式'deny'=>array('/^(/system/audit)$/') // 禁止访问哪些URL的正则表达式),'AUDIT'=>array('permit'=>array('/^(/system/audit)$/'),//允许访问的URL正则表达式'deny'=>array('/^((/system/(clouds|device).*)$/')));
上述是垂直权限的拍卖,倘诺境遇了平行权限的难题,如客商A获取客商B的地点新闻或然退换其他顾客音讯,对于那个敏感数据接口都亟待增添对顾客的论断,这一步平日都在具体的逻辑落成中得以完结。

域名注册

4 URL过滤

在进入逻辑管理早前,参加对URubiconL的参数过滤,如/site/{num}/policy
节制num地点为整数等,假若不是参数则一直回到违法参数,设定一个url项目清单,不在不在url清单中的必要直接谢绝,那样能预防开荒中的api走漏。rest
api接口日常会用到GET,POST,PUT,DELETE,未达成的点子则一贯再次来到方法不容许,对于POST,PUT方法的多少利用json格式,并且在步入逻辑前验证是还是不是json,非法重返json格式错误。

2,全体权认证

5 首要意义加密传输

率先步推荐SSL加密传输,同期对于系统中驷不如舌的效率做加密传输,如证书,一些数码,配置的备份功能,同一时间还得保证全数相应的权限,这一步会在授权中提到。

声明您的域名全体权,能够通过HTML文件上传或包涵META标识。

6 速率限定

需要速率节制,依据api_key大概客户来判定某段日子的伸手次数,将该数据更新到内部存款和储蓄器数据库(redis,memcached),到达最大数即不收受该客商的伏乞,同期那样还能利用到内部存款和储蓄器数据库key在一依期刻自动过期的特征。在php中得以采纳APC,Alternative
PHP Cache (APCState of Qatar是一个开放自由的PHP opcode
缓存。它的靶子是提供二个猖獗、
开放,和宏观的框架用于缓存和优化PHP的中间代码。在回去时设置X-Rate-Limit-Reset:当前岁月段剩余秒数,APC的演示代码如下:
phpRoute::filter('api.limit', function(){$key = sprintf('api:%s', Auth::user()->api_key);// Create the key if it doesn't existCache::add($key, 0, 60);// Increment by 1$count = Cache::increment($key);// Fail if hourly requests exceededif ($count > Config::get('api.requests_per_hour')){App::abort(403, 'Hourly request limit exceeded');}});

奥门新浦京官方网站 5

7 错误管理

对此私自的,以致系统出错的等供给都开展记录,一些重大的操作,如登陆,注册等都经过日记接口输出浮现。有三个集结的失误接口,对于400两种和500各个的失实都有照料的错误码和有关消息提示,如401:未授权;403:已经鉴权,不过并未有相应权限。如不识其余url:{"result":"Invalid URL!"},错误的央浼参数{"result":"json format error"},不容许的秘诀:{"result":"Method Not Allowed"},违规参数等。下边所说的都以单状态码,相同的时间还可能有多状态码,表示部分中标,部分字符违法等。示举例下:

奥门新浦京官方网站 6

 

全部权认证

8 首要ID不透明处理

在系统部分冰雪聪明效率上,比方/user/1123
可收获id=1123顾客的音讯,为了防卫辞书遍历攻击,可对id进行url62可能uuid管理,那样管理的id是必经之路的,并且如故字符安全的。

3,OAuth Keys

9 其他注意事项

(1)央浼数据,对于POST,DELETE方法中的数据都使用json格式,当然不是说rest布局不协理xml,由于xml太不佳拆解剖判,对于好多的施用json已经丰裕,近一些的动向也是json越来越流行,并且json格式也不会有xml的一些苦尽甘来难题,如xxe。使用json格式近日能幸免扫描器自动扫描。
(2)再次来到数据统一编码格式,统风度翩翩重返类型,如Content-Type:
application/json; charset=”UTF-8″
(3)在逻辑达成中,json解码之后张开参数验证恐怕转义操作,第一步json格式验证,第二步具体参数验证基本上能防卫大多数的注入难题了。
(4)在传输进程中,选取SSL保险传输安全。
(5)存款和储蓄安全,首要音讯加密存款和储蓄,如认证音讯hash保存。

一句话来讲,尽量采取SSL。

谷歌(Google卡塔尔(قطر‎将提供你OAuth客户密钥和OAuth秘密密钥。

奥门新浦京官方网站 7

Oauth keys

4, Google API控制台

在Google
API控制台创制顾客端ID。

奥门新浦京官方网站 8

Google API控制台

奥门新浦京官方网站 9

Google API控制台

接下来您就能够瞥见你的顾客端ID和密钥。

奥门新浦京官方网站 10

安顿好的Google Oauth消息

config.php

你能够在src文件夹找到这一个文件,在这里处您须求配备使用程序OAuth密钥,Consumer
keys和重定向回调UEscortL。

// OAuth2 Settings, you can get these keys at https://code.google.com/apis/console Step 6 keys  
'oauth2_client_id' => 'App Client ID',  
'oauth2_client_secret' => 'App Client Secret',  
'oauth2_redirect_uri' => 'http://yoursite.com/gplus/index.php',  

// OAuth1 Settings Step 3  keys.  
'oauth_consumer_key' => 'OAuth Consumer Key',  
'oauth_consumer_secret' => 'OAuth Consumer Secret',

google_login.php

谷歌(GoogleState of Qatar plus登陆系统,你只须要在index.php中加载那一个文件。

<?php  
require_once 'src/apiClient.php';  
require_once 'src/contrib/apiOauth2Service.php';  
session_start();  
$client = new apiClient();  
setApplicationName("Google Account Login");  
$oauth2 = new apiOauth2Service($client);  
if (isset($_GET['code']))  
{  
$client->authenticate();  
$_SESSION['token'] = $client->getAccessToken();  
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];  
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));  
}  
if (isset($_SESSION['token'])) {  
$client->setAccessToken($_SESSION['token']);  
}  
if (isset($_REQUEST['logout'])) {  
unset($_SESSION['token']);  
unset($_SESSION['google_data']); //Google session data unset  
$client->revokeToken();  
}  
if ($client->getAccessToken())  
{  
$user = $oauth2->userinfo->get();  
$_SESSION['google_data']=$user; // Storing Google User Data in Session  
header("location: home.php");  
$_SESSION['token'] = $client->getAccessToken();  
} else {  
$authUrl = $client->createAuthUrl();  
}  
if(isset($personMarkup)):  
print $personMarkup;  
endif 
if(isset($authUrl))  
{  
echo "<a class="login" href="$authUrl">Google Account Login</a>";  
} else {  
echo "<a class="logout" href="?logout">Logout</a>";  
}  
?>

home.php

在那地大家需求向前边创建的user表插入谷歌 plus的session新闻。代码如下:

<?php  
session_start();  
include('db.php'); //Database Connection.  
if (!isset($_SESSION['google_data'])) {  
// Redirection to application home page.  
header("location: index.php");  
}  
else 
{  
//echo print_r($userdata);  
$userdata=$_SESSION['google_data'];  
$email =$userdata['email'];  
$googleid =$userdata['id'];  
$fullName =$userdata['name'];  
$firstName=$userdata['given_name'];  
$lastName=$userdata['family_name'];  
$gplusURL=$userdata['link'];  
$avatar=$userdata['picture'];  
$gender=$userdata['gender'];  
$dob=$userdata['birthday'];  
//Execture query  
$sql=mysql_query("insert into users(email,fullname,firstname,lastname,google_id,gender,dob,profile_image,gpluslink) values('$email','$fullName','$firstName','$lastName','$googleid','$gender','$dob','$avatar','$gplusURL')");  
?>

db.php

数据库配置文件。

<?php  
$mysql_hostname = "localhost";  
$mysql_user = "username";  
$mysql_password = "password";  
$mysql_database = "databasename";  
$bd = mysql_connect($mysql_hostname, $mysql_user, $mysql_password) or die("Could not connect database");  
mysql_select_db($mysql_database, $bd) or die("Could not select database");  
?>

发表评论

电子邮件地址不会被公开。 必填项已用*标注