Removed the obsolete PDF UXSS functionality (MODSEC-96).

This commit is contained in:
ivanr 2009-12-04 23:33:47 +00:00
parent 853b1f9fc8
commit 839b7f81e0
7 changed files with 2 additions and 710 deletions

View File

@ -3,7 +3,7 @@
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \ MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
re re_operators re_actions re_tfns re_variables \ re re_operators re_actions re_tfns re_variables \
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \ msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
persist_dbm msc_reqbody pdf_protect msc_geo acmp msc_lua msc_release persist_dbm msc_reqbody msc_geo acmp msc_lua msc_release
MSC_TEST = re re_operators re_actions re_tfns re_variables \ MSC_TEST = re re_operators re_actions re_tfns re_variables \
msc_logging msc_xml msc_multipart modsecurity \ msc_logging msc_xml msc_multipart modsecurity \
@ -11,7 +11,7 @@ MSC_TEST = re re_operators re_actions re_tfns re_variables \
msc_reqbody msc_geo acmp msc_lua msc_release msc_reqbody msc_geo acmp msc_lua msc_release
MOD_SECURITY2_H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \ MOD_SECURITY2_H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \ msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h \
msc_geo.h acmp.h utf8tables.h msc_lua.h msc_release.h msc_geo.h acmp.h utf8tables.h msc_lua.h msc_release.h
CC = @APXS_CC@ CC = @APXS_CC@

View File

@ -21,7 +21,6 @@
#include "modsecurity.h" #include "modsecurity.h"
#include "msc_logging.h" #include "msc_logging.h"
#include "msc_util.h" #include "msc_util.h"
#include "pdf_protect.h"
#include "http_log.h" #include "http_log.h"
#if defined(WITH_LUA) #if defined(WITH_LUA)
@ -101,14 +100,6 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
/* Content injection. */ /* Content injection. */
dcfg->content_injection_enabled = NOT_SET; dcfg->content_injection_enabled = NOT_SET;
/* PDF XSS protection. */
dcfg->pdfp_enabled = NOT_SET;
dcfg->pdfp_secret = NOT_SET_P;
dcfg->pdfp_timeout = NOT_SET;
dcfg->pdfp_token_name = NOT_SET_P;
dcfg->pdfp_only_get = NOT_SET;
dcfg->pdfp_method = NOT_SET;
/* Geo Lookups */ /* Geo Lookups */
dcfg->geo = NOT_SET_P; dcfg->geo = NOT_SET_P;
@ -438,20 +429,6 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
? parent->content_injection_enabled : child->content_injection_enabled); ? parent->content_injection_enabled : child->content_injection_enabled);
/* PDF XSS protection. */
merged->pdfp_enabled = (child->pdfp_enabled == NOT_SET
? parent->pdfp_enabled : child->pdfp_enabled);
merged->pdfp_secret = (child->pdfp_secret == NOT_SET_P
? parent->pdfp_secret : child->pdfp_secret);
merged->pdfp_timeout = (child->pdfp_timeout == NOT_SET
? parent->pdfp_timeout : child->pdfp_timeout);
merged->pdfp_token_name = (child->pdfp_token_name == NOT_SET_P
? parent->pdfp_token_name : child->pdfp_token_name);
merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET
? parent->pdfp_only_get : child->pdfp_only_get);
merged->pdfp_method = (child->pdfp_method == NOT_SET
? parent->pdfp_method : child->pdfp_method);
/* Geo Lookup */ /* Geo Lookup */
merged->geo = (child->geo == NOT_SET_P merged->geo = (child->geo == NOT_SET_P
? parent->geo : child->geo); ? parent->geo : child->geo);
@ -543,14 +520,6 @@ void init_directory_config(directory_config *dcfg) {
/* Content injection. */ /* Content injection. */
if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0; if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
/* PDF XSS protection. */
if (dcfg->pdfp_enabled == NOT_SET) dcfg->pdfp_enabled = 0;
if (dcfg->pdfp_secret == NOT_SET_P) dcfg->pdfp_secret = NULL;
if (dcfg->pdfp_timeout == NOT_SET) dcfg->pdfp_timeout = 10;
if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN";
if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 1;
if (dcfg->pdfp_method == NOT_SET) dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
/* Geo Lookup */ /* Geo Lookup */
if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL; if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
@ -1629,80 +1598,6 @@ static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
return NULL; return NULL;
} }
/* -- PDF Protection configuration -- */
static const char *cmd_pdf_protect(cmd_parms *cmd, void *_dcfg, int flag) {
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->pdfp_enabled = flag;
return NULL;
}
static const char *cmd_pdf_protect_secret(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->pdfp_secret = p1;
return NULL;
}
static const char *cmd_pdf_protect_timeout(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->pdfp_timeout = atoi(p1);
return NULL;
}
static const char *cmd_pdf_protect_token_name(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->pdfp_token_name = p1;
return NULL;
}
static const char *cmd_pdf_protect_intercept_get_only(cmd_parms *cmd, void *_dcfg,
int flag)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
dcfg->pdfp_only_get = flag;
return NULL;
}
static const char *cmd_pdf_protect_method(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
if (strcasecmp(p1, "TokenRedirection") == 0) {
dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
} else
if (strcasecmp(p1, "ForcedDownload") == 0) {
dcfg->pdfp_method = PDF_PROTECT_METHOD_FORCED_DOWNLOAD;
} else {
return (const char *)apr_psprintf(cmd->pool,
"ModSecurity: Unrecognised parameter value for SecPdfProtectMethod: %s", p1);
}
return NULL;
}
/* -- Geo Lookup configuration -- */ /* -- Geo Lookup configuration -- */
static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
@ -2016,54 +1911,6 @@ const command_rec module_directives[] = {
"marker for a skipAfter target" "marker for a skipAfter target"
), ),
AP_INIT_FLAG (
"SecPdfProtect",
cmd_pdf_protect,
NULL,
RSRC_CONF,
"enable PDF protection module."
),
AP_INIT_TAKE1 (
"SecPdfProtectSecret",
cmd_pdf_protect_secret,
NULL,
RSRC_CONF,
"secret that will be used to construct protection tokens."
),
AP_INIT_TAKE1 (
"SecPdfProtectTimeout",
cmd_pdf_protect_timeout,
NULL,
RSRC_CONF,
"duration for which protection tokens will be valid."
),
AP_INIT_TAKE1 (
"SecPdfProtectTokenName",
cmd_pdf_protect_token_name,
NULL,
RSRC_CONF,
"name of the protection token. The name 'PDFTOKEN' is used by default."
),
AP_INIT_FLAG (
"SecPdfProtectInterceptGETOnly",
cmd_pdf_protect_intercept_get_only,
NULL,
RSRC_CONF,
"whether or not to intercept only GET and HEAD requess. Defaults to true."
),
AP_INIT_TAKE1 (
"SecPdfProtectMethod",
cmd_pdf_protect_method,
NULL,
RSRC_CONF,
"protection method to use. Can be 'TokenRedirection' (default) or 'ForcedDownload'"
),
AP_INIT_TAKE1 ( AP_INIT_TAKE1 (
"SecRequestBodyAccess", "SecRequestBodyAccess",
cmd_request_body_access, cmd_request_body_access,

View File

@ -24,7 +24,6 @@
#include "modsecurity.h" #include "modsecurity.h"
#include "apache2.h" #include "apache2.h"
#include "http_main.h" #include "http_main.h"
#include "pdf_protect.h"
#include "msc_logging.h" #include "msc_logging.h"
#include "msc_util.h" #include "msc_util.h"
@ -634,15 +633,6 @@ static int hook_request_late(request_rec *r) {
init_directory_config(msr->txcfg); init_directory_config(msr->txcfg);
/* Perform the PDF tests now. */
rc = pdfp_check(msr);
if (rc > 0) {
/* The PDF protection module has decided it needs to
* redirect the current transaction. So we let it do that.
*/
return rc;
}
if (msr->txcfg->is_enabled == 0) { if (msr->txcfg->is_enabled == 0) {
if (msr->txcfg->debuglog_level >= 4) { if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Processing disabled, skipping (hook request_late)."); msr_log(msr, 4, "Processing disabled, skipping (hook request_late).");
@ -1171,9 +1161,6 @@ static void register_hooks(apr_pool_t *mp) {
*/ */
ap_register_output_filter("MODSECURITY_OUT", output_filter, ap_register_output_filter("MODSECURITY_OUT", output_filter,
NULL, AP_FTYPE_CONTENT_SET - 3); NULL, AP_FTYPE_CONTENT_SET - 3);
ap_register_output_filter("PDFP_OUT", pdfp_output_filter,
NULL, AP_FTYPE_CONTENT_SET);
} }
/* Defined in apache2_config.c */ /* Defined in apache2_config.c */

View File

@ -446,14 +446,6 @@ struct directory_config {
/* Content injection. */ /* Content injection. */
int content_injection_enabled; int content_injection_enabled;
/* PDF XSS Protection. */
int pdfp_enabled;
const char *pdfp_secret;
int pdfp_timeout;
const char *pdfp_token_name;
int pdfp_only_get;
int pdfp_method;
/* Geo Lookup */ /* Geo Lookup */
geo_db *geo; geo_db *geo;

View File

@ -21,7 +21,6 @@
#include "modsecurity.h" #include "modsecurity.h"
#include "re.h" #include "re.h"
#include "pdf_protect.h"
#define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F'))) #define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
@ -488,12 +487,6 @@ static void init_msr(void)
dcfg->data_dir = "."; dcfg->data_dir = ".";
dcfg->webappid = "default"; dcfg->webappid = "default";
dcfg->content_injection_enabled = 0; dcfg->content_injection_enabled = 0;
dcfg->pdfp_enabled = 0;
dcfg->pdfp_secret = NULL;
dcfg->pdfp_timeout = 10;
dcfg->pdfp_token_name = "PDFPTOKEN";
dcfg->pdfp_only_get = 1;
dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
dcfg->geo = NULL; dcfg->geo = NULL;
dcfg->cache_trans = MODSEC_CACHE_ENABLED; dcfg->cache_trans = MODSEC_CACHE_ENABLED;
dcfg->cache_trans_min = 15; dcfg->cache_trans_min = 15;

View File

@ -1,498 +0,0 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
*
* This product is released under the terms of the General Public Licence,
* version 2 (GPLv2). Please refer to the file LICENSE (included with this
* distribution) which contains the complete text of the licence.
*
* There are special exceptions to the terms and conditions of the GPL
* as it is applied to this software. View the full text of the exception in
* file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
* distribution.
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Breach Security, Inc.
* directly using the email address support@breach.com.
*
*/
#include "modsecurity.h"
#include "apache2.h"
#include "pdf_protect.h"
#include <ctype.h>
#include "apr_sha1.h"
#define DEFAULT_TIMEOUT 10
#define DEFAULT_TOKEN_NAME "PDFPTOKEN"
#define ATTACHMENT_MIME_TYPE "application/octet-stream"
#define NOTE_TWEAK_HEADERS "pdfp-note-tweakheaders"
#define NOTE_DONE "pdfp-note-done"
#define REDIRECT_STATUS HTTP_TEMPORARY_REDIRECT
#define DISPOSITION_VALUE "attachment;"
// TODO We need ID and REV values for the PDF XSS alert.
// TODO It would be nice if the user could choose the ID/REV/SEVERITY/MESSAGE, etc.
static char *encode_sha1_base64(apr_pool_t *mp, const char *data) {
unsigned char digest[APR_SHA1_DIGESTSIZE];
apr_sha1_ctx_t context;
/* Calculate the hash first. */
apr_sha1_init(&context);
apr_sha1_update(&context, data, strlen(data));
apr_sha1_final(digest, &context);
/* Now transform with transport-friendly hex encoding. */
return bytes2hex(mp, digest, APR_SHA1_DIGESTSIZE);
}
static char *create_hash(modsec_rec *msr,
const char *time_string)
{
const char *content = NULL;
if (msr->txcfg->pdfp_secret == NULL) {
msr_log(msr, 1, "PdfProtect: Unable to generate hash. Please configure SecPdfProtectSecret.");
return NULL;
}
/* Our protection token is made out of the client's IP
* address, the secret key, and the token expiry time.
*/
content = apr_pstrcat(msr->mp, msr->remote_addr, msr->txcfg->pdfp_secret,
time_string, NULL);
if (content == NULL) return NULL;
return encode_sha1_base64(msr->mp, content);
}
/**
*
*/
static char *create_token(modsec_rec *msr) {
apr_time_t current_time;
const char *time_string = NULL;
const char *hash = NULL;
int timeout = DEFAULT_TIMEOUT;
if (msr->txcfg->pdfp_timeout != -1) {
timeout = msr->txcfg->pdfp_timeout;
}
current_time = apr_time_sec(apr_time_now());
time_string = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(current_time + timeout));
if (time_string == NULL) return NULL;
hash = create_hash(msr, time_string);
if (hash == NULL) return NULL;
return apr_pstrcat(msr->mp, hash, "|", time_string, NULL);
}
/**
*
*/
static char *construct_new_uri(modsec_rec *msr) {
const char *token_parameter = NULL;
const char *new_uri = NULL;
const char *token = NULL;
const char *token_name = DEFAULT_TOKEN_NAME;
token = create_token(msr);
if (token == NULL) return NULL;
if (msr->txcfg->pdfp_token_name != NULL) {
token_name = msr->txcfg->pdfp_token_name;
}
token_parameter = apr_pstrcat(msr->mp, token_name, "=", token, NULL);
if (token_parameter == NULL) return NULL;
if (msr->r->args == NULL) { /* No other parameters. */
new_uri = apr_pstrcat(msr->mp, msr->r->uri, "?", token_parameter, "#PDFP", NULL);
} else { /* Preserve existing paramters. */
new_uri = apr_pstrcat(msr->mp, msr->r->uri, "?", msr->r->args, "&",
token_parameter, "#PDFP", NULL);
}
return (char *)new_uri;
}
/**
*
*/
static char *extract_token(modsec_rec *msr) {
char *search_string = NULL;
char *p = NULL, *t = NULL;
const char *token_name = DEFAULT_TOKEN_NAME;
if ((msr->r == NULL)||(msr->r->args == NULL)) {
return NULL;
}
if (msr->txcfg->pdfp_token_name != NULL) {
token_name = msr->txcfg->pdfp_token_name;
}
search_string = apr_pstrcat(msr->mp, msr->txcfg->pdfp_token_name, "=", NULL);
if (search_string == NULL) return NULL;
p = strstr(msr->r->args, search_string);
if (p == NULL) return NULL;
t = p = p + strlen(search_string);
while ((*t != '\0')&&(*t != '&')) t++;
return apr_pstrmemdup(msr->mp, p, t - p);
}
/**
*
*/
static int validate_time_string(const char *time_string) {
char *p = (char *)time_string;
while(*p != '\0') {
if (!isdigit(*p)) return 0;
p++;
}
return 1;
}
/**
*
*/
static int verify_token(modsec_rec *msr, const char *token, char **error_msg) {
unsigned int current_time, expiry_time;
const char *time_string = NULL;
const char *given_hash = NULL;
const char *hash = NULL;
const char *p = NULL;
if (error_msg == NULL) return 0;
*error_msg = NULL;
/* Split token into its parts - hash and expiry time. */
p = strstr(token, "|");
if (p == NULL) return 0;
given_hash = apr_pstrmemdup(msr->mp, token, p - token);
time_string = p + 1;
if (!validate_time_string(time_string)) {
*error_msg = apr_psprintf(msr->mp, "PdfProtect: Invalid time string: %s",
log_escape_nq(msr->mp, time_string));
return 0;
}
expiry_time = atoi(time_string);
/* Check the hash. */
hash = create_hash(msr, time_string);
if (strcmp(given_hash, hash) != 0) {
*error_msg = apr_psprintf(msr->mp, "PdfProtect: Invalid hash: %s (expected %s)",
log_escape_nq(msr->mp, given_hash), log_escape_nq(msr->mp, hash));
return 0;
}
/* Check time. */
current_time = apr_time_sec(apr_time_now());
if (current_time > expiry_time) {
*error_msg = apr_psprintf(msr->mp, "PdfProtect: Token has expired.");
return 0;
}
return 1;
}
/**
*
*/
apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
modsec_rec *msr = (modsec_rec *)f->ctx;
if (msr == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
"ModSecurity: Internal Error: Unable to retrieve context in PDF output filter.");
ap_remove_output_filter(f);
return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
}
if (msr->txcfg->pdfp_enabled == 1) {
// TODO Should we look at err_headers_out too?
const char *h_content_type = apr_table_get(f->r->headers_out, "Content-Type");
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: r->content_type=%s, header C-T=%s",
log_escape_nq(msr->mp, f->r->content_type),
log_escape_nq(msr->mp, h_content_type));
}
/* Have we been asked to tweak the headers? */
if (apr_table_get(f->r->notes, NOTE_TWEAK_HEADERS) != NULL) {
/* Yes! */
apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
f->r->content_type = ATTACHMENT_MIME_TYPE;
}
/* Check if we've already done the necessary work in
* the first phase.
*/
if (apr_table_get(f->r->notes, NOTE_DONE) != NULL) {
/* We have, so return straight away. */
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
/* Proceed to detect dynamically-generated PDF files. */
// TODO application/x-pdf, application/vnd.fdf, application/vnd.adobe.xfdf,
// application/vnd.adobe.xdp+xml, application/vnd.adobe.xfd+xml, application/vnd.pdf
// application/acrobat, text/pdf, text/x-pdf ???
if (((f->r->content_type != NULL)&&(strcasecmp(f->r->content_type, "application/pdf") == 0))
|| ((h_content_type != NULL)&&(strcasecmp(h_content_type, "application/pdf") == 0)))
{
request_rec *r = f->r;
const char *token = NULL;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Detected a dynamically-generated PDF in %s",
log_escape_nq(msr->mp, r->uri));
}
/* If we are configured with ForcedDownload protection method then we
* can do our thing here and finish early.
*/
if (msr->txcfg->pdfp_method == PDF_PROTECT_METHOD_FORCED_DOWNLOAD) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically "
"generated PDF file.");
}
apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
f->r->content_type = ATTACHMENT_MIME_TYPE;
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
/* If we are here that means TokenRedirection is the desired protection method. */
/* Is this a non-GET request? */
if ((f->r->method_number != M_GET)&&
((msr->txcfg->pdfp_only_get == 1)||(msr->txcfg->pdfp_only_get == -1))
) {
/* This is a non-GET request and we have been configured
* not to intercept it. So we are going to tweak the headers
* to force download.
*/
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically "
"generated PDF file and non-GET method.");
}
apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
f->r->content_type = ATTACHMENT_MIME_TYPE;
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
/* Locate the protection token. */
token = extract_token(msr);
if (token == NULL) { /* No token. */
char *new_uri = NULL;
/* Create a new URI with the protection token inside. */
new_uri = construct_new_uri(msr);
if (new_uri != NULL) {
/* Redirect user to the new URI. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request without a token - "
"redirecting to %s.", log_escape_nq(msr->mp, new_uri));
}
apr_table_set(r->headers_out, "Location", new_uri);
ap_remove_output_filter(f);
return send_error_bucket(msr, f, REDIRECT_STATUS);
}
} else { /* Token found. */
char *my_error_msg = NULL;
/* Verify the token is valid. */
if (verify_token(msr, token, &my_error_msg)) { /* Valid. */
/* Do nothing - serve the PDF file. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request with a valid token "
"- serving PDF file normally.");
}
/* Fall through. */
} else { /* Not valid. */
/* The token is not valid. We will tweak the response
* to prevent the PDF file from opening in the browser.
*/
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 9, "PdfProtect: PDF request with an invalid token "
"- serving file as attachment.");
}
apr_table_set(r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
r->content_type = ATTACHMENT_MIME_TYPE;
/* Fall through. */
}
}
}
}
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
/**
*
*/
int pdfp_check(modsec_rec *msr) {
const char *token = NULL;
char *uri = NULL;
char *p = NULL;
if (msr->txcfg->pdfp_enabled != 1) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Not enabled here.");
}
return 0;
}
if (msr->txcfg->pdfp_method != PDF_PROTECT_METHOD_TOKEN_REDIRECTION) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Configured with ForcedDownload as protection method, "
"skipping detection on the inbound.");
}
return 0;
}
/* Then determine whether we need to act at
* all. If the request is not for a PDF file
* return straight away.
*/
if (msr->r->uri == NULL) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Unable to inspect URI because it is NULL.");
}
return -1; /* Error. */
}
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: URI=%s, filename=%s, QUERY_STRING=%s.",
log_escape_nq(msr->mp, msr->r->uri), log_escape_nq(msr->mp, msr->r->filename),
log_escape_nq(msr->mp, msr->r->args));
}
uri = apr_pstrdup(msr->mp, msr->r->uri);
if (uri == NULL) return -1; /* Error. */
ap_str_tolower(uri);
/* Attempt to figure out if this is a request for a PDF file. We are
* going to be liberal and look for the extension anywhere in the URI,
* not just at the end.
*/
p = strstr(uri, ".pdf");
if (p == NULL) {
/* We do not think this is a PDF file. */
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: No indication in the URI this is a "
"request for a PDF file.");
}
return 0;
}
/* Ignore request methods other than GET and HEAD if
* configured to do so.
*
* TODO: Code here is only GET, not GET|HEAD as comment states
*/
if ((msr->r->method_number != M_GET)&&(msr->txcfg->pdfp_only_get != 0)) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Not intercepting request "
"(method=%s/%d).", log_escape_nq(msr->mp, msr->r->method), msr->r->method_number);
}
return 0;
}
/* We make a note for ourselves that we've already handled
* the request.
*/
apr_table_set(msr->r->notes, NOTE_DONE, "1");
/* Locate the protection token. */
token = extract_token(msr);
if (token == NULL) { /* No token. */
char *new_uri = NULL;
/* Create a new URI with the protection token inside. */
new_uri = construct_new_uri(msr);
if (new_uri == NULL) return DECLINED;
/* Redirect user to the new URI. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request without a token - redirecting to %s.",
log_escape_nq(msr->mp, new_uri));
}
apr_table_set(msr->r->headers_out, "Location", new_uri);
return REDIRECT_STATUS;
} else { /* Token found. */
char *my_error_msg = NULL;
/* Verify the token is valid. */
if (verify_token(msr, token, &my_error_msg)) { /* Valid. */
/* Do nothing - serve the PDF file. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request with a valid token - "
"serving PDF file normally.");
}
return 0;
} else { /* Not valid. */
/* The token is not valid. We will tweak the response
* to prevent the PDF file from opening in the browser.
*/
// TODO Log alert
/* Changing response headers before response generation phase takes
* place is not really reliable. Although we do this we also make
* a note for ourselves (in the output filter) to check the headers
* again just before they are sent back to the end user.
*/
apr_table_set(msr->r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
msr->r->content_type = ATTACHMENT_MIME_TYPE;
apr_table_set(msr->r->notes, NOTE_TWEAK_HEADERS, "1");
/* Proceed with response (PDF) generation. */
return 0;
}
}
return 0;
}

View File

@ -1,29 +0,0 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2009 Breach Security, Inc. (http://www.breach.com/)
*
* This product is released under the terms of the General Public Licence,
* version 2 (GPLv2). Please refer to the file LICENSE (included with this
* distribution) which contains the complete text of the licence.
*
* There are special exceptions to the terms and conditions of the GPL
* as it is applied to this software. View the full text of the exception in
* file MODSECURITY_LICENSING_EXCEPTION in the directory of this software
* distribution.
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Breach Security, Inc.
* directly using the email address support@breach.com.
*
*/
#ifndef _PDF_PROTECT_H_
#define _PDF_PROTECT_H_
#define PDF_PROTECT_METHOD_TOKEN_REDIRECTION 1
#define PDF_PROTECT_METHOD_FORCED_DOWNLOAD 2
apr_status_t DSOLOCAL pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in);
int DSOLOCAL pdfp_check(modsec_rec *msr);
#endif