资讯专栏INFORMATION COLUMN

集成阿里云滑动验证(python)

bang590 / 1413人阅读

摘要:阿里云的服务数据风控下面有项滑动验证适合有人机验证场景的应用接入所谓滑动验证是在需要进行人机识别时前端出现验证滑块通过拖动滑块到末尾实现验证如果阿里云认为此次验证风险稍高可能出现点击汉字的认证等如果风险太高验证会直接拒绝集成过程基本是按照阿

阿里云的服务 数据风控下面有项滑动验证, 适合有人机验证场景的应用接入.

所谓滑动验证, 是在需要进行人机识别时, 前端出现验证滑块, 通过拖动滑块到末尾, 实现验证. 如果阿里云认为此次验证风险稍高, 可能出现点击汉字的认证等, 如果风险太高, 验证会直接拒绝.

集成过程基本是按照 阿里云官方文档 来进行的.

开通滑动验证服务之后, 阿里云控制台会给出前后端的示例代码, 其中appkey是根据用户不同分配的不通的key.

前端代码如下所示:




  
  示例-WEB版

  
  
  
    





用户名:
密码:

其中标记不可更改的地方就不要更改. 可以看到, 在验证通过之后, console会打印出session, sig, token等几个验证返回变量, 连同scene一起, 通过表单返回业务后台, 由后台调用阿里云滑动验证服务进行校验.

python后台方面, 首先需要

pip install aliyun-python-sdk-jaq

安装阿里云滑动验证的python sdk
python的后台代码大致如下:

# coding: utf-8
import requests
from aliyunsdkcore import client
from aliyunsdkjaq.request.v20161123 import AfsCheckRequest
from aliyunsdkcore.profile import region_provider
from app.libs.configure import config

region_provider.modify_point("Jaq", "cn-hangzhou", "jaq.aliyuncs.com")

clt = client.AcsClient(config.ALIYUN_OSS_ACCESS_KEY, config.ALIYUN_OSS_ACCESS_SECRET, "cn-hangzhou")


def check_aliyun_captcha(session, sig, token, scene):
    request = AfsCheckRequest.AfsCheckRequest()
    # 必填参数:请求来源: 1:Android端; 2:iOS端; 3:PC端及其他
    request.set_Platform(3)
    request.set_Session(session)
    request.set_Sig(sig)
    request.set_Token(token)
    request.set_Scene(scene)
    result = clt.do_action_with_exception(request)
    print result

这只是个简单示例, print出了返回结果. 这个返回结果是json序列化的string, 需要将其反序列化进行结果判定. 如果Data元素是true的话, 证明校验通过, 可以进行下面的业务逻辑.
同样的, 这里还有一点没有处理, 就是do_action_with_exception的抛出ServerException的问题. 应当catch处理.

如果验证通过的话, 阿里云返回:

{"Data":true,"ErrorMsg":"success.","ErrorCode":0}

但只能验证一次, 第二次同样参数执行的话, 会返回:

{"Data":false,"ErrorMsg":"invalid sig parameter.","ErrorCode":400}

是为了防止暴力尝试等.

同时必须说明, 阿里云的这项服务我认为并不稳定, 集成中间出现了一直invalid sig的报错. 后来经与技术支持沟通才ok. 并且这块的文档友好程度等还比较欠缺.

另: 我还按照阿里云api文档(滑动验证api, 公共参数, 签名机制)的说明写了段代码, 不使用aliyun-python-sdk, 手动拼接请求.同样发现了很多问题.
比如文档中有一段


这个签名值应当不是随便写的. 使用文档中要求的HMAC-SHA1签名算法, 无论是用python像如下这样书写:

from hashlib import sha1
import hmac
from base64 import b64encode

hashed = hmac.new("testsecret&", string_to_sign, sha1)
signature = b64encode(hashed.digest())
print signature

还是像如下用Java算签名:

import javax.crypto.Mac;  
import javax.crypto.SecretKey;  
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;  
  
public class HMACSHA1 {  
  
    private static final String MAC_NAME = "HmacSHA1";    
    private static final String ENCODING = "UTF-8";    

    public static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {           
        byte[] data=encryptKey.getBytes(ENCODING);  
        SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);   
        Mac mac = Mac.getInstance(MAC_NAME);   
        mac.init(secretKey);    
        byte[] text = encryptText.getBytes(ENCODING);    
        return mac.doFinal(text);    
    }
    
    public static void main(String[] args) throws Exception{
        byte[] bytes = HMACSHA1.HmacSHA1Encrypt("string_to_sign", "testsecret&");
        System.out.println(Base64.encodeBase64String(bytes));
    }
} 

string_to_sign用文档中给出的替换, 我的两段程序算出的是一致的, 但都跟文档中给出的不一致. 不清楚为何基础算法会不一致, 难道是文档不够新.

如果我用python如下根据api文档实现自己的后台请求方法的话:

import random
from urllib import quote
from hashlib import sha1
import hmac
import requests
from base64 import b64encode
import datetime

def utcnow_isostr():
    dt = datetime.datetime.utcnow()
    return datetime.datetime.strftime(dt, "%Y-%m-%dT%H:%M:%SZ")

def quote_ali(element):
    return quote(str(element)).replace("+", "20%").replace("*", "2A%").replace("%7E", "~")

def build_afs_check_request(session, sig, token, scene):
    m = dict()
    m["Action"] = "AfsCheck"
    m["Format"] = "JSON"
    m["Version"] = "2016-11-23"
    m["AccessKeyId"] = config.ALIYUN_OSS_ACCESS_KEY
    m["SignatureMethod"] = "HMAC-SHA1"
    m["Timestamp"] = utcnow_isostr()
    m["SignatureVersion"] = "1.0"
    m["SignatureNonce"] = str(int(random.random()*1000000))
    m["token"] = token
    m["sig"] = sig
    m["session"] = session
    m["scene"] = scene
    m["platform"] = 3
    ks = m.keys()
    ks.sort()
    query_list = list()
    for k in ks:
        query_list.append(k + "=" + quote_ali(m[k]))
    string_to_sign = "GET&%2F&" + "&".join(query_list)
    print string_to_sign
    base_query_string = "&".join(query_list)
    hashed = hmac.new(config.ALIYUN_OSS_ACCESS_SECRET + "&", string_to_sign, sha1)
    signature = b64encode(hashed.digest())
    print signature
    url = "http://jaq.aliyuncs.com/?{}&Signature={}".format(base_query_string, quote_ali(signature))
    print url
    return url

def custom_check_aliyun_captcha(session, sig, token, scene):
    url = build_afs_check_request(session, sig, token, scene)
    resp = requests.get(url)
    print resp.content

这么去请求的话会报Signature不一致, 果不出所料.

基于以上诡异的表现, 我觉得阿里云滑动验证作为外部服务并不友好或成熟. 更倾向于用自己做的一些验证码服务, 虽然会简单些, 更容易被攻破, 至少稳定, 提供的qps更高.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40727.html

相关文章

  • 首次公开,整理12年积累的博客收藏夹,零距离展示《收藏夹吃灰》系列博客

    摘要:时间永远都过得那么快,一晃从年注册,到现在已经过去了年那些被我藏在收藏夹吃灰的文章,已经太多了,是时候把他们整理一下了。那是因为收藏夹太乱,橡皮擦给设置私密了,不收拾不好看呀。 ...

    Harriet666 评论0 收藏0
  • Linux设备如何接入阿里IoT平台

    摘要:名词解释设备端阿里云物联网平台提供的即设备端,用于设备端开发。设备厂商将设备端集成到设备上,设备便可通过该安全地接入到阿里云物联网平台。设备证书设备证书指和,是阿里云物联网平台认证设备的标识。 本文以在Ubuntu x86_64系统上编译设备端C语言SDK为例,介绍设备上云的配置和开发过...

    沈建明 评论0 收藏0
  • 100%移植阿里移动测试技术,竟仅需1周?!——移动测试专有(3)——内容详解

    摘要:换句话说就是,让测试更有针对性。得益于强大的测试技术,兼容性测试的检出率远远高于业界水平。同时,在性能测试方面,即提供了项性能指标曲线性能分析,更提供了强大的内存泄漏和内存溢出的检测和分析能力。 摘要: Android兼容性测试旨在帮助解决Android应用在不同真机机型上的各类兼容性问题,包括 Crash/ANR分析、6项性能分析、UI检测、3个版本的覆盖安装检测等。Android兼...

    付永刚 评论0 收藏0
  • 阿里平台发送短信

    摘要:获取阿里云访问密钥为了使用短信发送,您必须申请阿里云的访问密钥。国际港澳台消息只能使用国际港澳台短信模版发送短信。 1.获取阿里云访问密钥 为了使用短信发送API-Python SDK,您必须申请阿里云的访问密钥。 阿里云访问秘钥是阿里云为用户使用 API(非控制台)来访问其云资源设计的安全口令。您可以用它来签名 API 请求内容以通过服务端的安全验证。 该访问秘钥成对(AccessK...

    CODING 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<