safe-redirect.js 1.46 KB
/**
 * 安全重定向 301、302跳转只允许白名单中的URL
 *
 * @author: Aiden Xu<aiden.xu@yoho.cn>
 * @date: 2016/6/22
 */

'use strict';

const url = require('url');
const domains = require('../../config/safe-domain').domains;
const _ = require('lodash');


/**
 * 检查域名安全性
 *
 * @param uri
 */
const safeRedirect = (uri) => {
    let formalUrl = url.parse(uri); // 匹配标准的URL
    let informalUrl = uri.match(/^\/\/(.+)/); // 尝试匹配 '//' 开头的不规范的URL
    let matchFunc;

    if (formalUrl.protocol) {
        // 在白名单中尝试匹配
        matchFunc = (item)=> {
            return item === formalUrl.host;
        };
    } else if (informalUrl && informalUrl.length > 0) {
        matchFunc = (item)=> {
            return item === informalUrl[1];
        };
    }


    return _.some(domains, matchFunc) ? uri : '/';
};

/**
 * 安全重定向中间件
 *
 * @returns {function(*, *=, *)}
 */
const middleware = () => {
    return (req, res, next) => {
        const expressRedirect = res.redirect;

        res.redirect = function(uri) {
            const safeUri = safeRedirect(uri);
            let args = [];

            if (arguments.length === 1) {
                args[0] = safeUri;
            } else if (arguments.length === 2) {
                args[1] = safeUri;
            }

            return expressRedirect.apply(res, args);
        };

        next();
    };
};


module.exports = {
    safeRedirect,
    middleware
};