django-增加功能-百度推送工具开发

百度站长平台官方提供的推送接口 工具的作用是批量提交网站链接,推送给百度收录网站链接 。

百度主动推送工具

增加文章的render:

在视图函数中添加html对界面的映射。
tool/views.py:


# 百度主动推送
def BD_pushview(request):
    return render(request, 'tool/bd_push.html')

在前端中设计ui

tool/bd_push.html:

<div class="mb-3">
    <div class="form-group">
        <label>接口调用地址:</label>
        <input type="url" class="form-control rounded-0" id="form-url"
               placeholder="例:http://data.zz.baidu.com/urls?site=www.example.com&token=NpU0****tTQAlBV"
               required>
        <small class="form-text text-muted">注:请填写百度站长平台提供给您的接口调用地址</small>
    </div>
    <div class="form-group">
        <label>网址链接:</label>
        <textarea class="form-control rounded-0" id="form-urls" rows="5" required
                  placeholder="示例如下:&#10;http://www.example.com/mip/&#10;http://www.example.com/mip/1.html&#10;http://www.example.com/mip/2.php"></textarea>
        <small class="form-text text-muted">注:提交的链接的域名必须与接口中site保持一直才能推送成功</small>
    </div>
    <button type="submit" class="btn btn-info btn-sm rounded-0" id="start-push">开始推送</button>
</div>

通过ajax将我们输入的信息来进行数据打包并传送到后端

ajax
Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。
Ajax = 异步 JavaScript 和 XML 或者是 HTML(标准通用标记语言的子集)。
Ajax 是一种用于创建快速动态网页的技术。
Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。

当然我们需要对传入的数据进行简单的空值判断:

var url = $('#form-url').val();
    var urls = $('#form-urls').val();
    if (url.length == 0 | urls.length == 0) {
        alert('接口地址和网址链接内容都不能为空!');
        return false
    };

调用csrf格式的引用:

$.ajaxSetup({
        data: {
            csrfmiddlewaretoken: CSRF
        }
    });

csrfCSRF跨站点请求伪造(Cross—Site Request Forgery)

其实对于csrf相信大家使用django的时候应该不会陌生。
在django教程中是这样说的

CSRF
背景知识:浏览器在发送请求的时候,会自动带上当前域名对应的cookie内容,发送给服务端,不管这个请求是来源A网站还是其它网站,只要请求的是A网站的链接,就会带上A网站的cookie。浏览器的同源策略并不能阻止CSRF攻击,因为浏览器不会停止js发送请求到服务端,只是在必要的时候拦截了响应的内容。或者说浏览器收到响应之前它不知道该不该拒绝。

攻击过程:用户登陆A网站后,攻击者自己开发一个B网站,这个网站会通过js请求A网站,比如用户点击了某个按钮,就触发了js的执行。

预防:

  • Double Submit Cookie

攻击者是利用cookie随着http请求发送的特性来攻击。但攻击都不知道 cookie里面是什么。

Django中是在表单中加一个隐藏的 csrfmiddlewaretoken,在提交表单的时候,会有 cookie 中的内容做比对,一致则认为正常,不一致则认为是攻击。由于每个用户的 token 不一样,B网站上的js代码无法猜出token内容,对比必然失败,所以可以起到防范作用。

  • Synchronizer Token

和上面的类似,但不使用 cookie,服务端的数据库中保存一个 session_csrftoken,表单提交后,将表单中的 token 和 session 中的对比,如果不一致则是攻击。

这个方法实施起来并不困难,但它更安全一些,因为网站即使有 xss 攻击,也不会有泄露token的问题。

通缩的说也就是:
django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在 cookie 里。然后每次 POST 请求都会带上这个 token,
这样就能避免被 CSRF 攻击。

这样子看起来似乎没毛病,但是评论中的第三个问题,每次刷新页面,form表单中的token都会刷新,而cookie中的token却只在每次登录时刷新。我对csrftoken的验证方式起了疑问,后来看了一段官方文档的解释。

When validating the ‘csrfmiddlewaretoken’ field value, only the secret, not the full token, is compared with the secret in the cookie value. This allows the use of ever-changing tokens. While each request may use its own token, the secret remains common to all.
This check is done by CsrfViewMiddleware.

官方文档中说到,检验token时,只比较secret是否和cookie中的secret值一样,而不是比较整个token。
我又有疑问了,同一次登录,form表单中的token每次都会变,而cookie中的token不便,django把那个salt存储在哪里才能保证验证通过呢。直到看到源码。

csrf案例分析

受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=bob&a... 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。

    黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。

    这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。 
def _compare_salted_tokens(request_csrf_token, csrf_token):
    # Assume both arguments are sanitized -- that is, strings of
    # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
    return constant_time_compare(
        _unsalt_cipher_token(request_csrf_token),
        _unsalt_cipher_token(csrf_token),
    )

def _unsalt_cipher_token(token):
    """
    Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
    CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
    the second half to produce the original secret.
    """
    salt = token[:CSRF_SECRET_LENGTH]
    token = token[CSRF_SECRET_LENGTH:]
    chars = CSRF_ALLOWED_CHARS
    pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
    secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
    return secret

token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。
django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。
同样也不难解释,为什么ajax请求时,需要从cookie中拿取token添加到请求头中。

增加tool.js文件代码,对文内容id为form-url和form-urls的部分进行数据获取,并通过post的方式将数据进行ajax打包发送。并编辑简单的回调信息,当信息传输成功的时候,显示$('.push-result').html(ret.msg);

//baidu links push api
function push_spider(CSRF, URL) {
    var url = $('#form-url').val();
    var urls = $('#form-urls').val();
    if (url.length == 0 | urls.length == 0) {
        alert('接口地址和网址链接内容都不能为空!');
        return false
    };

    $.ajaxSetup({
        data: {
            csrfmiddlewaretoken: CSRF
        }
    });
    $('.push-result').html('<i class="fa fa-spinner fa-pulse fa-3x"></i>');
    $.ajax({
        type: 'post',
        url: URL,
        data: {
            'url': url,
            'url_list': urls
        },
        dataType: 'json',
        success: function(ret) {
            $('.push-result').html(ret.msg);
        },
    })
}
}

在tool中通过id="form-url"进行选择获取百度站长平台提供的接口调用地址 id="form-urls"获取要提交的链接地址。对数据进行重组在通过调用。

在apis中编写路由函数

编写push_urls构造推送头,对数据进行post,回去回调信息。

def push_urls(url, urls):
    '''根据百度站长提供的API推送链接'''
    headers = {
        'User-Agent': 'curl/7.12.1',
        'Host': 'data.zz.baidu.com',
        'Content - Type': 'text / plain',
        'Content - Length': '83'
    }
    try:
        html = requests.post(url, headers=headers, data=urls, timeout=5).text
        return html
    except:
        return "{'error':404,'message':'请求超时,接口地址错误!'}"

对上述重组的数据进行post,函数调用:


from .apis.bd_push import push_urls

# 百度主动推送
def BD_pushview(request):
    return render(request, 'tool/bd_push.html')

@require_POST
def bd_api_view(request):
    if request.is_ajax():
        data = request.POST
        url = data.get('url')
        urls = data.get('url_list')
        info = push_urls(url, urls)
        return JsonResponse({'msg': info})
    return JsonResponse({'msg': 'miss'})

通过view视图函数调用路由api。

工具的来源刚开始是在https://tendcode.com/中,这篇文章简单的解析一些功能的实现流程,和开发步骤。

本作品采用《CC 协议》,转载必须注明作者和本文链接
文章!!首发于我的博客Stray_Camel(^U^)ノ~YO
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!