diff --git a/inc/config.php b/inc/config.php
index 633cdd33..08b01ead 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -200,6 +200,9 @@
// Used to salt secure tripcodes ("##trip") and poster IDs (if enabled).
$config['secure_trip_salt'] = ')(*&^%$#@!98765432190zyxwvutsrqponmlkjihgfedcba';
+ // Used to salt poster passwords.
+ $config['secure_password_salt'] = 'wKJSb7M5SyzMcFWD2gPO3j2RYUSO9B789!@#$%^&*()';
+
/*
* ====================
* Flood/spam settings
diff --git a/inc/functions.php b/inc/functions.php
index 767dfc06..66cd6fa7 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -3082,3 +3082,8 @@ function strategy_first($fun, $array) {
return array('defer');
}
}
+
+function hashPassword($password) {
+ global $config;
+ return hash('sha3-256', $password . $config['secure_password_salt']);
+}
diff --git a/install.php b/install.php
index bc3ba7d4..7663a503 100644
--- a/install.php
+++ b/install.php
@@ -881,6 +881,7 @@ if ($step == 0) {
$config['cookies']['salt'] = substr(base64_encode(sha1(rand())), 0, 30);
$config['secure_trip_salt'] = substr(base64_encode(sha1(rand())), 0, 30);
+ $config['secure_password_salt'] = substr(base64_encode(sha1(rand())), 0, 30);
echo Element('page.html', array(
'body' => Element('installer/config.html', array(
diff --git a/post.php b/post.php
index 642e8057..0a7959c2 100644
--- a/post.php
+++ b/post.php
@@ -530,10 +530,12 @@ function handle_delete(Context $ctx)
$password = &$_POST['password'];
- if ($password == '') {
+ if (empty($password)) {
error($config['error']['invalidpassword']);
}
+ $password = hashPassword($_POST['password']);
+
$delete = [];
foreach ($_POST as $post => $value) {
if (preg_match('/^delete_(\d+)$/', $post, $m)) {
@@ -1009,11 +1011,16 @@ function handle_post(Context $ctx)
}
}
+ // We must do this check now before the passowrd is hashed and overwritten.
+ if (\mb_strlen($_POST['password']) > 20) {
+ error(\sprintf($config['error']['toolong'], 'password'));
+ }
+
$post['name'] = $_POST['name'] != '' ? $_POST['name'] : $config['anonymous'];
$post['subject'] = $_POST['subject'];
$post['email'] = str_replace(' ', '%20', htmlspecialchars($_POST['email']));
$post['body'] = $_POST['body'];
- $post['password'] = $_POST['password'];
+ $post['password'] = hashPassword($_POST['password']);
$post['has_file'] = (!isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || count($_FILES) > 0));
if (!$dropped_post) {
@@ -1204,9 +1211,6 @@ function handle_post(Context $ctx)
error($config['error']['toolong_body']);
}
}
- if (mb_strlen($post['password']) > 20) {
- error(sprintf($config['error']['toolong'], 'password'));
- }
}
wordfilters($post['body']);
diff --git a/templates/installer/config.html b/templates/installer/config.html
index 973328f5..00a5b241 100644
--- a/templates/installer/config.html
+++ b/templates/installer/config.html
@@ -88,6 +88,9 @@
+
+
+
diff --git a/templates/posts.sql b/templates/posts.sql
index 9c468c97..71bad994 100755
--- a/templates/posts.sql
+++ b/templates/posts.sql
@@ -13,7 +13,7 @@ CREATE TABLE IF NOT EXISTS ``posts_{{ board }}`` (
`files` text DEFAULT NULL,
`num_files` int(11) DEFAULT 0,
`filehash` text CHARACTER SET ascii,
- `password` varchar(20) DEFAULT NULL,
+ `password` varchar(64) DEFAULT NULL,
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
`sticky` int(1) NOT NULL,
`locked` int(1) NOT NULL,
diff --git a/tools/hash-passwords.php b/tools/hash-passwords.php
new file mode 100644
index 00000000..0002bd70
--- /dev/null
+++ b/tools/hash-passwords.php
@@ -0,0 +1,16 @@
+execute() or error(db_error($query));
+
+ while($entry = $query->fetch(\PDO::FETCH_ASSOC)) {
+ $update_query = prepare(\sprintf("UPDATE ``posts_%s`` SET `password` = :password WHERE `password` = :password_org", $uri));
+ $update_query->bindValue(':password', hashPassword($entry['password']));
+ $update_query->bindValue(':password_org', $entry['password']);
+ $update_query->execute() or error(db_error());
+ }
+}