• lighttpdmod_secdownload 防盗链


    Secure and Fast Downloading

    Module: mod_secdownload

    • Secure and Fast Downloading
      • Description
        • Important
      • Options
      • Examples
        • PHP Example
        • Ruby On Rails example, used in the context of a helper
        • Perl Example
        • Python example, usable with Django or any other Python web framework
        • C# Example
        • Webserver

     

    Description

    There are multiple ways to handle secured download mechanisms:

    1. use the webserver and the internal HTTP authentication
    2. use the application to authenticate and send the file
      through the application

    Both ways have limitations:

    Webserver:
    • + fast download
    • + no additional system load
    • -- inflexible authentication handling

    Application:

    • + integrated into the overall layout
    • + very flexible permission management
    • -- the download occupies an application thread/process

    A simple way to combine the two ways could be:

    1. app authenticates user and checks permissions to
    download the file.
    2. app redirects user to the file accessable by the webserver
    for further downloading.
    3. the webserver transfers the file to the user.

    As the webserver doesn't know anything about the permissions
    used in the app, the resulting URL would be available to every
    user who knows the URL.

    mod_secdownload removes this problem by introducing a way to
    authenticate a URL for a specified time. The application has
    to generate a token and a timestamp which are checked by the
    webserver before it allows the file to be downloaded by the
    webserver.

    The generated URL has to have the format:

    <uri-prefix>/<token>/<timestamp-in-hex>/<rel-path>
    which looks like "yourserver.com/bf32df9cdb54894b22e09d0ed87326fc/435cc8cc/secure.tar.gz"

    <token> is an MD5 of

    1. a secret string (user supplied)
    2. <rel-path> (starts with /)
    3. <timestamp-in-hex>

    As you can see, the token is not bound to the user at all. The
    only limiting factor is the timestamp which is used to
    invalidate the URL after a given timeout (secdownload.timeout).

     

    Important

    Be sure to choose a another secret than the one used in the
    examples, as this is the only part of the token that is not
    known to the user.

    Ensure that the token is also in hexadecimal. Depending on
    the programming language you use, there might be no extra
    step for this. For instance, in PHP, the MD5 function
    returns the Hex value of the digest. If, however, you use a
    language such as Java or Python, the extra step of converting
    the digest into Hex is needed (see the Python example below).

    If the user tries to fake the URL by choosing a random token,
    status 403 'Forbidden' will be sent out.

    If the timeout is reached, status 410 'Gone' will be
    sent. This used to be 408 'Request Timeout' in earlier versions.

    If token and timeout are valid, the <rel-path> is appended to
    the configured (secdownload.document-root) and passed to the
    normal internal file transfer functionality. This might lead to
    status 200 or 404.

    Options

     secdownload.secret        = <string>
    secdownload.document-root = <string>
    secdownload.uri-prefix = <string> (default: /)
    secdownload.timeout = <short> (default: 60 seconds)

    Examples

    Your application has to generate the correct URLs.

    PHP Example

      <?php

    $secret = "verysecret";
    $uri_prefix = "/dl/";

    # filename
    # please note file name starts with "/"
    $f = "/secret-file.txt";

    # current timestamp
    $t = time();

    $t_hex = sprintf("%08x", $t);
    $m = md5($secret.$f.$t_hex);

    # generate link
    printf('<a href="%s%s/%s%s">%s</a>',
    $uri_prefix, $m, $t_hex, $f, $f);
    ?>

    Ruby On Rails example, used in the context of a helper

    def gen_sec_link(rel_path)
        rel_path.sub!(/^([^\/])/,'/\1')     # Make sure it had a leading slash
        s_secret = 'verysecret'             # Secret string
        uri_prefix = '/dl/'                 # Arbitrary download prefix
        timestamp = "%08x" % Time.now.to_i  # Timestamp, to hex
        token = MD5::md5(s_secret + rel_path + timestamp).to_s    # Token Creation
        '%s%s/%s%s' % [uri_prefix, token, timestamp, rel_path]   # Return the properly formatted string
      end
    

      

    So in a view or helper:

    <%= link_to "Private Image", gen_sec_link("path/from/download-area/someimage.img") %>

     

    Perl Example

    #!/usr/bin/perl

    use CGI;
    use Digest::MD5 qw(md5 md5_hex md5_base64);

    $secret = "verysecret";
    $uri_prefix = "/static/";

    #filename
    $f = "/$request";

    #timestamp
    $t = time();

    $hex = sprintf("%08x", $t);
    $m = md5_hex($secret.$f.$t_hex);

    #link
    printf('<a href="%s%s/%s%s">%s</a>', $uri_prefix, $m, $t_hex, $f, $f);



    Python example, usable with Django or any other Python web framework

    def gen_sec_link(rel_path):
    import time, hashlib
    secret = 'verysecret'
    uri_prefix = '/dl/'
    hextime = "%08x" % time.time()
    token = hashlib.md5(secret + rel_path + hextime).hexdigest()
    return '%s%s/%s%s' % (uri_prefix, token, hextime, rel_path)



    Note: When using Django with non-ASCII file names (hashlib in Python 2.x does not handle non-ASCII strings properly, throwing the UnicodeDecodeError exception, unless bytestrings encoded in UTF-8 are supplied instead of the default unicode objects):

    def gen_securelink(rel_path):
    import time, hashlib
    from django.utils.http import urlquote
    rel_path = '/%s/%s' % (self.series.directory, self.filename)
    secret = "flylight"
    uri_prefix = "http://media.ongoing.ru/download/"
    hextime = "%08x" % time.time()
    token = hashlib.md5((secret + rel_path + hextime).encode('utf-8')).hexdigest()
    return '%s%s/%s%s' % (uri_prefix, token, hextime, urlquote(rel_path))

    (urlquote() can be replaced by urllib methods, of course.)

    C# Example

    //import library

    using System.Security.Cryptography;
    using System.Text;

    //function :
    public string GetHash(string hashMe) // function get MD5
    {
    MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
    UTF7Encoding encoder = new UTF7Encoding();
    Byte[] encStringBytes;
    encStringBytes = encoder.GetBytes(hashMe);
    encStringBytes = md5.ComputeHash(encStringBytes);
    string strHex = string.Empty;
    foreach (byte b in encStringBytes)
    strHex += String.Format("{0:x2}", b);
    return strHex;
    }
    public string GetCurrentEpochTimeInHex() // function get current epoch time in HEX
    {
    DateTime EpochTime = new DateTime(1970, 1, 1, 0, 0, 0);
    TimeSpan diff = DateTime.UtcNow - EpochTime;
    return ((long)diff.TotalSeconds).ToString("x");
    }
    public string GenerateSecureLink(string rel_path) // ex : rel_path = "/secret-file.txt";
    {
    string t_hex = GetCurrentEpochTimeInHex();
    string serect = "verysecret";
    string uri_prefix = "/dl/";
    string m = GetHash(serect + rel_path + t_hex);
    return String.Format("{0}{1}/{2}{3}", uri_prefix, m, t_hex, rel_path);
    }

    Reference make MD5 in C# : http://ok-cool.com/posts/read/125-php-md5-not-the-same-as-net-md5/

    Webserver

    The server has to be configured in the same way. The URI prefix and
    secret have to match: ::

      server.modules = ( ..., "mod_secdownload", ... )
    secdownload.secret = "verysecret"
    secdownload.document-root = "/home/www/servers/download-area/"
    secdownload.uri-prefix = "/dl/"
    secdownload.timeout = 10
  • 相关阅读:
    7天入门JavaScript,第一天
    linux 下 启动web项目报 java.net.UnknownHostException
    HashMap 和 Hashtable
    Servlet 两种跳转方式
    SpringMVC
    把当前时间(NSDate)转为字符串
    写入数据到Plist文件中时,第一次要创建一个空的数组,否则写入文件失败
    实现多个UIView之间切换的动画效果
    missing required architecture x86_64 in file 不支持64位
    获取IOS bundle中的文件
  • 原文地址:https://www.cnblogs.com/shuaixf/p/2285309.html
Copyright © 2020-2023  润新知