summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/default.rules4
-rw-r--r--doc/source/config.rst11
-rw-r--r--doc/source/encryption.rst2
-rw-r--r--doc/source/features.rst15
-rw-r--r--src/config.m41
-rw-r--r--src/php_snuffleupagus.h1
-rw-r--r--src/snuffleupagus.c6
-rw-r--r--src/sp_config.c1
-rw-r--r--src/sp_config.h8
-rw-r--r--src/sp_config_keywords.c5
-rw-r--r--src/sp_config_keywords.h1
-rw-r--r--src/sp_curl_verify_certificates.c33
-rw-r--r--src/sp_curl_verify_certificates.h15
-rw-r--r--src/tests/config/disabled_function_curl_verify_certs.ini1
-rw-r--r--src/tests/ensure_client_valid_certs.phpt18
-rw-r--r--src/tests/ensure_server_valid_certs.phpt18
16 files changed, 139 insertions, 1 deletions
diff --git a/config/default.rules b/config/default.rules
index 2bd3c48..6e443ea 100644
--- a/config/default.rules
+++ b/config/default.rules
@@ -7,6 +7,9 @@ sp.disable_xxe.enable();
7# use SameSite on session cookie 7# use SameSite on session cookie
8sp.cookie.name("PHPSESSID").samesite("lax"); 8sp.cookie.name("PHPSESSID").samesite("lax");
9 9
10# Always verify certificates
11sp.curl_verify_certificates.enable();
12
10# Harden the `chmod` function 13# Harden the `chmod` function
11sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop(); 14sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();
12 15
@@ -91,3 +94,4 @@ sp.disable_function.function("is_callable").param("var").value("passthru").drop(
91#File upload 94#File upload
92sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ph").drop(); 95sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ph").drop();
93sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ht").drop(); 96sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ht").drop();
97
diff --git a/doc/source/config.rst b/doc/source/config.rst
index e209ecb..d89d7f5 100644
--- a/doc/source/config.rst
+++ b/doc/source/config.rst
@@ -202,6 +202,17 @@ to explicitly whitelist some `stream wrappers <https://secure.php.net/manual/en/
202 sp.wrappers_whitelist.list("file,php,phar"); 202 sp.wrappers_whitelist.list("file,php,phar");
203 203
204 204
205Mandatory certificates validation
206^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
207
208:ref:`Mandatory certificate validation <mandatory-cert-validation>` ensures
209that it's not possible to turn off certificate validation for `cURL usage <https://secure.php.net/manual/en/book.curl.php>`__.
210
211::
212
213 sp.curl_verify_certificates.enable();
214
215
205Eval white and blacklist 216Eval white and blacklist
206^^^^^^^^^^^^^^^^^^^^^^^^ 217^^^^^^^^^^^^^^^^^^^^^^^^
207 218
diff --git a/doc/source/encryption.rst b/doc/source/encryption.rst
index dc5dadf..23f36b4 100644
--- a/doc/source/encryption.rst
+++ b/doc/source/encryption.rst
@@ -4,7 +4,7 @@ Cookies
4======= 4=======
5 5
6Some cookies-related features might prevent other extensions from hooking 6Some cookies-related features might prevent other extensions from hooking
7the `setcookie<https://secure.php.net/manual/en/function.setcookie.php>`__ 7the `setcookie <https://secure.php.net/manual/en/function.setcookie.php>`__
8function. Pay attention to the loading order of your extensions in this case. 8function. Pay attention to the loading order of your extensions in this case.
9 9
10auto_cookie_secure 10auto_cookie_secure
diff --git a/doc/source/features.rst b/doc/source/features.rst
index 540e982..f676468 100644
--- a/doc/source/features.rst
+++ b/doc/source/features.rst
@@ -344,6 +344,21 @@ Snuffleupagus can prevent the execution of this kind of file. A good practice
344would be to use a different user to run PHP than for administrating the website, 344would be to use a different user to run PHP than for administrating the website,
345and using this feature to lock this up. 345and using this feature to lock this up.
346 346
347
348.. _mandatory-cert-validation:
349
350Mandatory certificates validation
351^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
352
353It's a common practise to disable `certificate validation <https://en.wikipedia.org/wiki/Transport_Layer_Security>`__
354during development for convenience's sake. Unfortunately, it's equally common
355to forget to turn it back on.
356
357Snuffleupagus can prevent php code from turning off certificate validation
358for anything `cURL <https://secure.php.net/manual/en/book.curl.php>`__-based.
359
360
361
347.. _stream-wrapper-whitelist-feature: 362.. _stream-wrapper-whitelist-feature:
348 363
349Whitelist of stream-wrappers 364Whitelist of stream-wrappers
diff --git a/src/config.m4 b/src/config.m4
index 52b6d04..dc88661 100644
--- a/src/config.m4
+++ b/src/config.m4
@@ -7,6 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c"
7sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" 7sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c"
8sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" 8sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c"
9sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c" 9sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c"
10sources="$sources sp_curl_verify_certificates.c"
10 11
11PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, 12PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support,
12[ --enable-snuffleupagus Enable snuffleupagus support]) 13[ --enable-snuffleupagus Enable snuffleupagus support])
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h
index 41d9b77..9dc045c 100644
--- a/src/php_snuffleupagus.h
+++ b/src/php_snuffleupagus.h
@@ -32,6 +32,7 @@
32#include "sp_config.h" 32#include "sp_config.h"
33#include "sp_config_utils.h" 33#include "sp_config_utils.h"
34#include "sp_config_keywords.h" 34#include "sp_config_keywords.h"
35#include "sp_curl_verify_certificates.h"
35#include "sp_cookie_encryption.h" 36#include "sp_cookie_encryption.h"
36#include "sp_disable_xxe.h" 37#include "sp_disable_xxe.h"
37#include "sp_disabled_functions.h" 38#include "sp_disabled_functions.h"
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index 1a92f11..9f92397 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -96,6 +96,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
96 SP_INIT(snuffleupagus_globals->config.config_session); 96 SP_INIT(snuffleupagus_globals->config.config_session);
97 SP_INIT(snuffleupagus_globals->config.config_eval); 97 SP_INIT(snuffleupagus_globals->config.config_eval);
98 SP_INIT(snuffleupagus_globals->config.config_wrapper); 98 SP_INIT(snuffleupagus_globals->config.config_wrapper);
99 SP_INIT(snuffleupagus_globals->config.config_curl_verify_certificates);
99 100
100 snuffleupagus_globals->config.config_disabled_functions_reg 101 snuffleupagus_globals->config.config_disabled_functions_reg
101 ->disabled_functions = NULL; 102 ->disabled_functions = NULL;
@@ -143,6 +144,7 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
143 pefree(SNUFFLEUPAGUS_G(config.config_random), 1); 144 pefree(SNUFFLEUPAGUS_G(config.config_random), 1);
144 pefree(SNUFFLEUPAGUS_G(config.config_readonly_exec), 1); 145 pefree(SNUFFLEUPAGUS_G(config.config_readonly_exec), 1);
145 pefree(SNUFFLEUPAGUS_G(config.config_global_strict), 1); 146 pefree(SNUFFLEUPAGUS_G(config.config_global_strict), 1);
147 pefree(SNUFFLEUPAGUS_G(config.config_curl_verify_certificates), 1);
146 pefree(SNUFFLEUPAGUS_G(config.config_auto_cookie_secure), 1); 148 pefree(SNUFFLEUPAGUS_G(config.config_auto_cookie_secure), 1);
147 pefree(SNUFFLEUPAGUS_G(config.config_snuffleupagus), 1); 149 pefree(SNUFFLEUPAGUS_G(config.config_snuffleupagus), 1);
148 pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1); 150 pefree(SNUFFLEUPAGUS_G(config.config_disable_xxe), 1);
@@ -272,6 +274,10 @@ static PHP_INI_MH(OnUpdateConfiguration) {
272 hook_session(); 274 hook_session();
273 } 275 }
274 276
277 if (SNUFFLEUPAGUS_G(config).config_curl_verify_certificates->enable) {
278 hook_curl_verify_certificates();
279 }
280
275 if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { 281 if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) {
276 if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { 282 if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) {
277 zend_extension_entry.startup = NULL; 283 zend_extension_entry.startup = NULL;
diff --git a/src/sp_config.c b/src/sp_config.c
index 2480362..bc703a6 100644
--- a/src/sp_config.c
+++ b/src/sp_config.c
@@ -24,6 +24,7 @@ sp_config_tokens const sp_func[] = {
24 {.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION}, 24 {.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION},
25 {.func = parse_sloppy_comparison, .token = SP_TOKEN_SLOPPY_COMPARISON}, 25 {.func = parse_sloppy_comparison, .token = SP_TOKEN_SLOPPY_COMPARISON},
26 {.func = parse_wrapper_whitelist, .token = SP_TOKEN_ALLOW_WRAPPERS}, 26 {.func = parse_wrapper_whitelist, .token = SP_TOKEN_ALLOW_WRAPPERS},
27 {.func = parse_curl_verify_certificates, .token = SP_TOKEN_CURL_VERIFY_CERTIFICATES},
27 {NULL, NULL}}; 28 {NULL, NULL}};
28 29
29/* Top level keyword parsing */ 30/* Top level keyword parsing */
diff --git a/src/sp_config.h b/src/sp_config.h
index 9d58359..4d85cf2 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -55,6 +55,10 @@ typedef struct {
55 55
56typedef struct { 56typedef struct {
57 bool enable; 57 bool enable;
58} sp_config_curl_verify_certificates;
59
60typedef struct {
61 bool enable;
58} sp_config_random; 62} sp_config_random;
59 63
60typedef struct { 64typedef struct {
@@ -162,6 +166,7 @@ typedef struct {
162 166
163typedef struct { 167typedef struct {
164 sp_config_random *config_random; 168 sp_config_random *config_random;
169 sp_config_curl_verify_certificates *config_curl_verify_certificates;
165 sp_config_sloppy *config_sloppy; 170 sp_config_sloppy *config_sloppy;
166 sp_config_unserialize *config_unserialize; 171 sp_config_unserialize *config_unserialize;
167 sp_config_readonly_exec *config_readonly_exec; 172 sp_config_readonly_exec *config_readonly_exec;
@@ -264,6 +269,9 @@ typedef struct {
264// upload_validator 269// upload_validator
265#define SP_TOKEN_UPLOAD_SCRIPT ".script(" 270#define SP_TOKEN_UPLOAD_SCRIPT ".script("
266 271
272// cURL certificate verify
273# define SP_TOKEN_CURL_VERIFY_CERTIFICATES ".curl_verify_certificates"
274
267#define SP_TOKEN_LIST ".list(" 275#define SP_TOKEN_LIST ".list("
268 276
269int sp_parse_config(const char *); 277int sp_parse_config(const char *);
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index 93077c6..ee4d130 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -94,6 +94,11 @@ int parse_global_strict(char *line) {
94 line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL); 94 line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL);
95} 95}
96 96
97int parse_curl_verify_certificates(char *line) {
98 return parse_enable(
99 line, &(SNUFFLEUPAGUS_G(config).config_curl_verify_certificates->enable), NULL);
100}
101
97int parse_unserialize(char *line) { 102int parse_unserialize(char *line) {
98 bool enable = false, disable = false; 103 bool enable = false, disable = false;
99 sp_config_unserialize *unserialize = 104 sp_config_unserialize *unserialize =
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h
index ab58456..f7a4ca4 100644
--- a/src/sp_config_keywords.h
+++ b/src/sp_config_keywords.h
@@ -17,5 +17,6 @@ int parse_eval_whitelist(char *line);
17int parse_session(char *line); 17int parse_session(char *line);
18int parse_sloppy_comparison(char *line); 18int parse_sloppy_comparison(char *line);
19int parse_wrapper_whitelist(char *line); 19int parse_wrapper_whitelist(char *line);
20int parse_curl_verify_certificates(char *line);
20 21
21#endif // __SP_CONFIG_KEYWORDS_H 22#endif // __SP_CONFIG_KEYWORDS_H
diff --git a/src/sp_curl_verify_certificates.c b/src/sp_curl_verify_certificates.c
new file mode 100644
index 0000000..057ee29
--- /dev/null
+++ b/src/sp_curl_verify_certificates.c
@@ -0,0 +1,33 @@
1#include "php_snuffleupagus.h"
2#include "sp_config.h"
3
4ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
5
6PHP_FUNCTION(sp_curl_setopt) {
7 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
8 zend_string *protocol_name = NULL;
9 zval *zid, *zvalue;
10 zend_long options;
11
12 ZEND_PARSE_PARAMETERS_START(3, 3)
13 Z_PARAM_RESOURCE(zid)
14 Z_PARAM_LONG(options)
15 Z_PARAM_ZVAL(zvalue)
16 ZEND_PARSE_PARAMETERS_END();
17
18 if (options & CURLOPT_SSL_VERIFYPEER && zval_get_long(zvalue) != 1) {
19 sp_log_err("verify_vertificates", "Please don't deactivate server certificate validation");
20 } else if (options & CURLOPT_SSL_VERIFYHOST && zval_get_long(zvalue) != 2) {
21 sp_log_err("verify_vertificates", "Please don't deactivate client certificate validation");
22 }
23
24 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
25}
26
27int hook_curl_verify_certificates() {
28 TSRMLS_FETCH();
29
30 HOOK_FUNCTION("curl_setopt", sp_internal_functions_hook, PHP_FN(sp_curl_setopt));
31
32 return SUCCESS;
33}
diff --git a/src/sp_curl_verify_certificates.h b/src/sp_curl_verify_certificates.h
new file mode 100644
index 0000000..f4f680e
--- /dev/null
+++ b/src/sp_curl_verify_certificates.h
@@ -0,0 +1,15 @@
1#ifndef SP_CURL_VERIFY_CERTIFICATES_H
2#define SP_CURL_VERIFY_CERTIFICATES_H
3#include "php_snuffleupagus.h"
4
5#ifndef CURLOPT_SSL_VERIFYPEER
6#define CURLOPT_SSL_VERIFYPEER 64
7#endif
8
9#ifndef CURLOPT_SSL_VERIFYHOST
10#define CURLOPT_SSL_VERIFYHOST 81
11#endif
12
13int hook_curl_verify_certificates();
14
15#endif
diff --git a/src/tests/config/disabled_function_curl_verify_certs.ini b/src/tests/config/disabled_function_curl_verify_certs.ini
new file mode 100644
index 0000000..64d54a7
--- /dev/null
+++ b/src/tests/config/disabled_function_curl_verify_certs.ini
@@ -0,0 +1 @@
sp.curl_verify_certificates.enable();
diff --git a/src/tests/ensure_client_valid_certs.phpt b/src/tests/ensure_client_valid_certs.phpt
new file mode 100644
index 0000000..64c523c
--- /dev/null
+++ b/src/tests/ensure_client_valid_certs.phpt
@@ -0,0 +1,18 @@
1--TEST--
2Disable functions - Ensure that client certificates validation can't be disabled
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) die "skip";
6if (!extension_loaded("curl")) die "skip";
7?>
8--INI--
9sp.configuration_file={PWD}/config/disabled_function_curl_verify_certs.ini
10--FILE--
11<?php
12$ch = curl_init();
13curl_setopt($ch, CURLOPT_VERBOSE, '1');
14curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, '0');
15echo "1337";
16?>
17--EXPECTF--
18Fatal error: [snuffleupagus][verify_vertificates] Please don't deactivate client certificate validation in %s/tests/ensure_client_valid_certs.php on line %d
diff --git a/src/tests/ensure_server_valid_certs.phpt b/src/tests/ensure_server_valid_certs.phpt
new file mode 100644
index 0000000..7eaf1a4
--- /dev/null
+++ b/src/tests/ensure_server_valid_certs.phpt
@@ -0,0 +1,18 @@
1--TEST--
2Disable functions - Ensure that server certificates validation can't be disabled
3--SKIPIF--
4<?php
5if (!extension_loaded("snuffleupagus")) die "skip";
6if (!extension_loaded("curl")) die "skip";
7?>
8--INI--
9sp.configuration_file={PWD}/config/disabled_function_curl_verify_certs.ini
10--FILE--
11<?php
12$ch = curl_init();
13curl_setopt($ch, CURLOPT_VERBOSE, '1');
14curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, '0');
15echo "1337";
16?>
17--EXPECTF--
18Fatal error: [snuffleupagus][verify_vertificates] Please don't deactivate client certificate validation in %s/tests/ensure_server_valid_certs.php on line 3