Extension talk:Auth viaMySQL
Add topic
Security Risk
[edit]This login script is trivially exploited to login as any user. By simply altering the username portion of the cookie used you can change your login to any user you wish.
This is indeed a major problem. I got around this security issue by adding a hash to the cookie (Of course, change 'SECRET_HASH' to a secret passphrase):
function set_cookie($username, $user_id, $password_hash, $user_email, $login_time) {
$hash = sha1($username . 'SECRET_HASH') ;
setcookie("mysql_active_user",
serialize(array($username, $user_id, $password_hash, $user_email, $login_time, $hash)), time()+60*60*24*100, "/") ;
$this->active_user_name = $username ;
$this->active_user_id = $user_id ;
$this->active_user_password = $password_hash ;
$this->active_user_email = $user_email ;
$this->active_user_login_time = $login_time ;
$this->active_user_hash = $hash ;
}
You should then update the clear_cookie() and the way you set your cookie accordingly.
And then just add the following in the distribute_cookie_data() function:
if ($this->active_user_hash != sha1($this->active_user_name . 'SECRET_HASH')) {
$this->clear_cookie();
}
Like this, users won't be able to switch easily to an admin user.
- Almost right. You should use HMAC-SHA256 because even though hash($username|$key) is not as easy to foil as using hash($key|$username) would be, it is still vulnerable to a collision-attack on $username. Bruteforce searching for an admin username collision is almost feasible on a modern desktop with a fast GPU, especially when using SHA1. Instead use a Hash-based Message Authentication Code that is designed to be the proper cryptographic primitive for such a job, HMAC. More info:
- Fortunately, if you got PHP5, using HMAC is almost just as simple as not using SHA1:
$hash = hash_hmac('sha256', $username, 'sEkritKEY_');
- And of course change the check in distribute_cookie_data accordingly. 94.212.50.232 11:53, 19 December 2011 (UTC)
In your login scripts for your web page add something like:
[edit]$command = "SELECT * FROM users WHERE Name='".$userName."';" ;
$result = mysql_query($command, $DBConnection);
$account = mysql_fetch_assoc($result) ;
if ($account)
{
$current_mw_timecode = gmdate( 'YmdHis' ) ;
$MySQLActiveUserData->set_cookie($account['Name'],
$account['id'],
$account['password'],
$account['email'],
$current_mw_timecode) ;
}
is wrong and did not work for my mediawiki v1.14.0;
This one worked (table/row names are different):
$command = "SELECT * FROM user WHERE user_name='".$userName."';";
$result = mysql_query($command, $DBConnection);
$account = mysql_fetch_assoc($result) ;
if ($account)
{
$current_mw_timecode = gmdate( 'YmdHis' ) ;
$MySQLActiveUserData->set_cookie($account['user_name'],
$account['user_id'],
$account['user_password'],
$account['user_email'],
$current_mw_timecode) ;
}
where exactly should the login script go? This would be a nice clarification. Thanks,
Instructions Are Very Confusing
[edit]- Now that it's talking about "MediaWiki Authentication via MySQL", but where to tell the MySQL database info, such as, hostname, database name, dababase username, password, and table name, etc.?
- Why the MySQLActiveUser.php file needs to be in the directory just BEFORE the MediaWiki installation directory? I want to have the authentication for the MediaWiki, not for the entire Apache website.
- "in your login/logout scritps" are especially confusing. What and where are the scripts? Why don't we just modify the LocalSettings.php to give some basic settings (including require_once, database info, etc.)?
Hope someone could make it simpler and clearer.
It would be nice that it is working as this:
- Download the Auth_viaMySQL extension to ./extensions directory
- Modify LocalSettings.php
- Users just need to click "Log in / create accout" at the up-right of the MW page to log in, and
- click the "Log out" to log out.
this is how i solved my problem
[edit]Of course the code needs a bit of cleaning-up but it works
require_once('../MySQLActiveUser.php'); global $MySQLActiveUserData ; global $DBConnection ; $username = $_POST['username']; $password = $_POST['password']; $username = stripslashes($username); $password = stripslashes($password); $password = md5($password); $username = mysql_real_escape_string($username); $password = mysql_real_escape_string($password); $command = "SELECT * FROM <your_user_table> WHERE username='".$username."' AND password='".$password."';"; $result = mysql_query($command) or die(mysql_error()); $account = mysql_fetch_assoc($result); if ($account) { $current_mw_timecode = gmdate( 'YmdHis' ) ; $MySQLActiveUserData->set_cookie($account['username'], $account['user_id'], $account['password'], $account['office_email'], $current_mw_timecode) ; } else { echo "<strong>login</strong> fail"; }
- What if the main web page does NOT use authentication?
- The MySQL database for user accounts is on another machine for another website in the LAN.
Make the above fix work
[edit]You have to put the above connection script into your existing login routine in your index.php or wherever you used to login to your MySQL database.
The following lines need to be changed to reflect the actual column header from your existing database:
$MySQLActiveUserData->set_cookie($account['username'], $account['user_id'], $account['password'], $account['user_email'], $current_mw_timecode);
Hook Auth_viaMySQL failed to return a value
[edit]When I use the Auth_viaMySQL.php as it is I get the following error:
- Hook Auth_viaMySQL failed to return a value
To fix that, you have to change the following lines:
function Auth_viaMySQL( &$user, &$result ) { global $MySQLActiveUserData; $MySQLActiveUserData->distribute_cookie_data()Â ;
to:
function Auth_viaMySQL( $user, &$result ) { global $MySQLActiveUserData; $MySQLActiveUserData->distribute_cookie_data()Â ;
See the change with the variable &$user that becomes $user.
MW 1.18.0 w/vector skin
[edit]In Auth_viaMySQL.php, setting personal_urls to null results in '<0>' being displayed for each var. Unsetting the vars fixes this for me.
Change this:
function PersonalUrls_killLogout(&$personal_urls, $title) {
$personal_urls['logout'] = null ;
$personal_urls['login'] = null ;
$personal_urls['anonlogin'] = null ;
return true ;
}
to:
function PersonalUrls_killLogout(&$personal_urls, $title) {
unset($personal_urls['logout'], $personal_urls['login'], $personal_urls['anonlogin']) ;
return true ;
}