Ignore:
Timestamp:
May 11, 2009, 5:45:00 PM (13 years ago)
Author:
charles
Message:

(1.5x) backport r8358, 8359 to 1.5x/ branch for 1.53

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/1.5x/libtransmission/rpc-server.c

    r8357 r8378  
    3030#include "transmission.h"
    3131#include "bencode.h"
     32#include "crypto.h"
    3233#include "list.h"
    3334#include "platform.h"
     
    3738#include "utils.h"
    3839#include "web.h"
     40
     41/* session-id is used to make cross-site request forgery attacks difficult.
     42 * Don't disable this feature unless you really know what you're doing!
     43 * http://en.wikipedia.org/wiki/Cross-site_request_forgery
     44 * http://shiflett.org/articles/cross-site-request-forgeries
     45 * http://www.webappsec.org/lists/websecurity/archive/2008-04/msg00037.html */
     46#define REQUIRE_SESSION_ID
    3947
    4048#define MY_NAME "RPC Server"
     
    5866    char *             whitelistStr;
    5967    tr_list *          whitelist;
     68
     69    char *             sessionId;
     70    time_t             sessionIdExpiresAt;
    6071
    6172#ifdef HAVE_ZLIB
     
    446457}
    447458
    448 static void
    449 handle_request( struct evhttp_request * req,
    450                 void *                  arg )
     459static char*
     460get_current_session_id( struct tr_rpc_server * server )
     461{
     462    const time_t now = time( NULL );
     463
     464    if( !server->sessionId || ( now >= server->sessionIdExpiresAt ) )
     465    {
     466        int i;
     467        const int n = 48;
     468        const char * pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     469        const size_t pool_size = strlen( pool );
     470        char * buf = tr_new( char, n+1 );
     471
     472        for( i=0; i<n; ++i )
     473            buf[i] = pool[ tr_cryptoRandInt( pool_size ) ];
     474        buf[n] = '\0';
     475
     476        tr_free( server->sessionId );
     477        server->sessionId = buf;
     478        server->sessionIdExpiresAt = now + (60*60); /* expire in an hour */
     479    }
     480
     481    return server->sessionId;
     482}
     483
     484
     485static tr_bool
     486test_session_id( struct tr_rpc_server * server, struct evhttp_request * req )
     487{
     488    const char * ours = get_current_session_id( server );
     489    const char * theirs = evhttp_find_header( req->input_headers, TR_RPC_SESSION_ID_HEADER );
     490    const tr_bool success =  theirs && !strcmp( theirs, ours );
     491    return success;
     492}
     493
     494static void
     495handle_request( struct evhttp_request * req, void * arg )
    451496{
    452497    struct tr_rpc_server * server = arg;
     
    455500    {
    456501        const char * auth;
    457         char *       user = NULL;
    458         char *       pass = NULL;
     502        char * user = NULL;
     503        char * pass = NULL;
    459504
    460505        evhttp_add_header( req->output_headers, "Server", MY_REALM );
    461506
    462507        auth = evhttp_find_header( req->input_headers, "Authorization" );
    463 
    464508        if( auth && !strncasecmp( auth, "basic ", 6 ) )
    465509        {
     
    475519        if( !isAddressAllowed( server, req->remote_host ) )
    476520        {
    477             send_simple_response( req, 401,
     521            send_simple_response( req, 403,
    478522                "<p>Unauthorized IP Address.</p>"
    479523                "<p>Either disable the IP address whitelist or add your address to it.</p>"
     
    506550            handle_clutch( req, server );
    507551        }
     552#ifdef REQUIRE_SESSION_ID
     553        else if( !test_session_id( server, req ) )
     554        {
     555            const char * sessionId = get_current_session_id( server );
     556            char * tmp = tr_strdup_printf(
     557                "<p>Please add this header to your requests:</p>"
     558                "<p><code>%s: %s</code></p>"
     559                "<p>This requirement is to make "
     560                "<a href=\"http://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a>"
     561                " attacks more difficult.</p>",
     562                TR_RPC_SESSION_ID_HEADER, sessionId );
     563            evhttp_add_header( req->output_headers, TR_RPC_SESSION_ID_HEADER, sessionId );
     564            send_simple_response( req, 409, tmp );
     565            tr_free( tmp );
     566        }
     567#endif
    508568        else if( !strncmp( req->uri, "/transmission/rpc", 17 ) )
    509569        {
Note: See TracChangeset for help on using the changeset viewer.