From 7761a074509e404fcfc6f333fbdfe89b56e48878 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Thu, 31 Jul 2008 20:21:51 -0600 Subject: [PATCH] Implement secret auto-generation. Only works if this directory is writable. Signed-off-by: Edward Z. Yang --- .gitignore | 1 + README.txt | 10 ++++------ csrf-magic.php | 26 ++++++++++++++++++++++++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d7fb30b..69aa7ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /js-test/*.js /js-test/*.bak /js-test/*/ +/csrf-secret.php diff --git a/README.txt b/README.txt index ae44c69..8995170 100644 --- a/README.txt +++ b/README.txt @@ -99,7 +99,9 @@ For example, this is a recommended configuration: function csrf_startup() { // This is a secret value that must be set in order to enable username - // and IP based checks. Don't show this to anyone. + // and IP based checks. Don't show this to anyone. A secret id will + // automatically be generated for you if the directory csrf-magic.php + // is placed in is writable. csrf_conf('secret', 'ABCDEFG123456'); // This enables JavaScript rewriting and will ensure your AJAX calls @@ -157,13 +159,9 @@ my fail for the first page load. Subsequent page loads will work properly. * Minify csrf-magic.js for performance. - * Optional PHP5 exception support. - * Auto-generate secret. - * Make "first time" session more robust by double-submitting. - - * Test manual JavaScript overloading instructions. + * (?) Make "first time" session more robust by double-submitting. * Account for JavaScript generated-forms with some JavaScript that loads into some global onsubmit handler and checks form submissions accordingly. diff --git a/csrf-magic.php b/csrf-magic.php index 0e339d4..0205e4c 100644 --- a/csrf-magic.php +++ b/csrf-magic.php @@ -152,7 +152,7 @@ function csrf_check($fatal = true) { * Retrieves a valid token for a particular context. */ function csrf_get_token() { - $secret = $GLOBALS['csrf']['secret']; + $secret = csrf_get_secret(); csrf_start(); // These are "strong" algorithms that don't require per se a secret if (session_id()) return 'sid:' . sha1($secret . session_id()); @@ -180,7 +180,7 @@ function csrf_callback() { function csrf_check_token($token) { if (strpos($token, ':') === false) return false; list($type, $value) = explode(':', $token, 2); - $secret = $GLOBALS['csrf']['secret']; + $secret = csrf_get_secret(); switch ($type) { case 'sid': return $value === sha1($secret . session_id()); @@ -224,6 +224,28 @@ function csrf_start() { } } +/** + * Retrieves the secret, and generates one if necessary. + */ +function csrf_get_secret() { + if ($GLOBALS['csrf']['secret']) return $GLOBALS['csrf']['secret']; + $dir = dirname(__FILE__); + $file = $dir . '/csrf-secret.php'; + $secret = ''; + if (file_exists($file)) { + include $file; + return $secret; + } + if (is_writable($dir)) { + for ($i = 0; $i < 32; $i++) $secret .= '\\x' . dechex(mt_rand(32, 126)); + $fh = fopen($file, 'w'); + fwrite($fh, '