Browse Source

[mod_secdownload] new directives modify hash path (fixes #646, fixes #1904)

secdownload.path-segments = <number>
  include only given number of path segments in hash digest calculation

secdownload.hash-querystr = "enable" | "disable"
  include the query string in the hash digest calculation

x-ref:
  "secdownload.path_elements support"
  https://redmine.lighttpd.net/issues/646
  "mod_secdownload option to include url GET parameters in md5"
  https://redmine.lighttpd.net/issues/1904
personal/stbuehler/mod-csrf
Glenn Strauss 5 years ago
parent
commit
afce434e0b
  1. 38
      src/mod_secdownload.c
  2. 1
      tests/lighttpd.conf
  3. 16
      tests/mod-secdownload.t

38
src/mod_secdownload.c

@ -96,6 +96,8 @@ typedef struct {
secdl_algorithm algorithm;
unsigned int timeout;
unsigned short path_segments;
unsigned short hash_querystr;
} plugin_config;
typedef struct {
@ -282,6 +284,8 @@ SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
{ "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "secdownload.timeout", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ "secdownload.algorithm", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
{ "secdownload.path-segments", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
{ "secdownload.hash-querystr", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 6 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@ -299,12 +303,16 @@ SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
s->doc_root = buffer_init();
s->uri_prefix = buffer_init();
s->timeout = 60;
s->path_segments = 0;
s->hash_querystr = 0;
cv[0].destination = s->secret;
cv[1].destination = s->doc_root;
cv[2].destination = s->uri_prefix;
cv[3].destination = &(s->timeout);
cv[4].destination = algorithm;
cv[5].destination = &(s->path_segments);
cv[6].destination = &(s->hash_querystr);
p->config_storage[i] = s;
@ -402,6 +410,8 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin
PATCH(uri_prefix);
PATCH(timeout);
PATCH(algorithm);
PATCH(path_segments);
PATCH(hash_querystr);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@ -425,6 +435,10 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin
PATCH(timeout);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.algorithm"))) {
PATCH(algorithm);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.path-segments"))) {
PATCH(path_segments);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.hash-querystr"))) {
PATCH(hash_querystr);
}
}
}
@ -499,6 +513,30 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
rel_uri = ts_str + 8;
if (p->conf.path_segments) {
const char *rel_uri_end = rel_uri;
unsigned int count = p->conf.path_segments;
do {
rel_uri_end = strchr(rel_uri_end+1, '/');
} while (rel_uri_end && --count);
if (rel_uri_end) {
buffer_copy_string_len(srv->tmp_buf, protected_path,
rel_uri_end - protected_path);
protected_path = srv->tmp_buf->ptr;
}
}
if (p->conf.hash_querystr && !buffer_is_empty(con->uri.query)) {
buffer *b = srv->tmp_buf;
if (protected_path != b->ptr) {
buffer_copy_string(b, protected_path);
}
buffer_append_string_len(b, CONST_STR_LEN("?"));
buffer_append_string_buffer(b, con->uri.query);
/* assign last in case b->ptr is reallocated */
protected_path = b->ptr;
}
if (!secdl_verify_mac(srv, &p->conf, protected_path, mac_str, mac_len)) {
con->http_status = 403;

1
tests/lighttpd.conf

@ -199,6 +199,7 @@ $HTTP["host"] == "vvv-sha256.example.org" {
secdownload.uri-prefix = "/sec/"
secdownload.timeout = 120
secdownload.algorithm = "hmac-sha256"
secdownload.hash-querystr = "enable"
}
$HTTP["host"] == "zzz.example.org" {

16
tests/mod-secdownload.t

@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
use Test::More tests => 15;
use Test::More tests => 16;
use LightyTest;
use Digest::MD5 qw(md5_hex);
use Digest::SHA qw(hmac_sha1 hmac_sha256);
@ -142,6 +142,20 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
ok($tf->handle_http($t) == 0, 'secdownload (hmac-sha256)');
## HMAC-SHA256
$f = "/index.html?qs=1";
$thex = sprintf("%08x", time);
$m = encode_base64url(hmac_sha256("/$thex$f", $secret));
$t->{REQUEST} = ( <<EOF
GET /sec/$m/$thex$f HTTP/1.0
Host: vvv-sha256.example.org
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
ok($tf->handle_http($t) == 0, 'secdownload (hmac-sha256) with hash-querystr');
$thex = sprintf("%08x", time - 1800);
$m = encode_base64url(hmac_sha256("/$thex$f", $secret));

Loading…
Cancel
Save