Basically I've got a game server in which had the password hash as sha1 and another as md5 for when new users registered an account. I decided to stick with sha1, however I want to be able for my users to change their password which will create them into sha1 from md5.
I've got the below code I've written up but it doesn't seem to work.
Basically, I want it to when they change their password it replaces the md5 with the sha1 hash password.
<?php
if(isSet($_POST['submit']))
{
$changePW = true;
}
?>
<?php
public function hashed($password)
{
return sha1($password . "xCg532%#%gdvf^5DGaa6&*rFTfg^FD4\$OIFThrR_gh(ugf*/");
}
?>
<?php
if(isset($changePW))
{
//host, username, password, dbName
$con=mysqli_connect("localhost","root","password","dbName");
$username = $_POST['username'];
$password = $_POST['passwordOld'];
$passwordNew1 = $_POST['passwordNew1'];
$passwordNew2 = $_POST['passwordNew2'];
$passwordHash = md5($password);
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$cmd = "SELECT COUNT(*) FROM users WHERE username = '" . $username . "' AND password = '" . $passwordHash . "'";
$result = mysqli_query($con,$cmd);
$row = mysqli_fetch_row($result);
if($row[0] == 1)
{
if($passwordNew1 == $passwordNew2)
{
$newHash = hashed($passwordNew1);
$cmd = "UPDATE users SET password = '$newHash' WHERE username = '$username'";
mysqli_query($con,$cmd);
}
else{
$passwordMatch = true;
}
}
else {
$detailsError = true;
}
//$hash = md5($password);
//mysqli_query($con,"INSERT INTO tutorials_tbl (name, hash) VALUES ('" . $username . "','" . $hash . "')");
mysqli_close($con);
}
?>
<head>
<style type="text/css">
.lblLabel{
width:165px;
display: inline-block;
}
</style>
</head>
<form name="login" method="post" action="change.php">
<fieldset style="width:350px;"><legend>Change Password Form</legend>
<label class="lblLabel">Username</label><input id="name" type="text" name="username" value=""><br />
<label class="lblLabel">Old Password</label><input type="password" name="passwordOld"><br />
<?php
if(isset($detailsError))
{ ?>
<span style="color: #F00; font-weight: bold;">Username or Password Incorrect</span>
<?php }
?>
<label class="lblLabel">New Password</label><input type="password" name="passwordNew1"><br />
<label class="lblLabel">Repeated New Password</label><input type="password" name="passwordNew2"><br />
<?php
if(isset($passwordMatch))
{ ?>
<span style="color: #F00; font-weight: bold;">Password's do not match</span>
<?php }
?>
<label class="lblLabel"> </label><input id="submit" type="submit" name="submit" value="Change Password"><br />
</fieldset>
</form>
It's calling to change the password under the password column to sha1, in the users table. All current passwords in the users table are md5 and need to be converted into sha1.
Sorry if this doesn't make sense.
Every password-storing-system must have the option to switch to a better hash algorithm, your problem is not a one-time migration problem. Good password hash algorithms like BCrypt have a cost factor, from time to time you have to increase this cost factor (because of faster hardware), then you need the exact same procedure as you need for the migration.
That leads to your biggest problem, SHA-1 is not appropriate to hash passwords, especially if it is salted with a constant salt. It is ways too fast and makes it easy to brute-force (3 Giga hashes per second with common hardware in 2013). That's why one should use a slow key-derivation function like BCrypt. If you take the effort to migrate your hashes, then better switch straight to BCrypt.
The usual way to switch to a better hash algorithm is to wait until the user logs in the next time (in contrast to your example, the user doesn't need to change the password then). Then you take this steps:
First try to verify the entered password with the new algorithm. New passwords and already converted passwords will not take longer for verification then.
If it does not match, compare it with the old hash algorithm.
Should the old hash value match, then you can calculate and store the new hash, since you know the password then.
This system can be extended to more than one migration. Just make sure that you first check for the newest algorithm, and afterwards for older algorithms. Then the login will take longer only the next time the user logs in, and new users are not affected by backwards compatibility issues.
That leaves the question of how to use BCrypt. PHP 5.5 will have it's own functions password_hash() and password_verify() ready. I recommend to use this excellent api, or it's compatibility pack for earlier PHP versions. The usage is very straightforward:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
➽ Keep in mind, that you need a database field with 60 characters in length, to store such hash-values.
As explained in my comment, what you'd want to do to make the transition in password storage as smooth as possible for the user is to hash everyone's password against SHA1 while leaving it MD5-hashed. Then, in your normal login logic, you'd MD5-hash the password, then SHA1-hash that.
As an aside, I'd use SHA2 for a hashing algorithm (just as fast, more secure, etc.)
<?php
public function hashSpecial($password)
{
return sha1($password . "xCg532%#%gdvf^5DGaa6&*rFTfg^FD4\$OIFThrR_gh(ugf*/");
}
public function hashForLogin($password)
{
return sha1(md5($password)
. "xCg532%#%gdvf^5DGaa6&*rFTfg^FD4\$OIFThrR_gh(ugf*/");
}
public function hashAllPasswords()
{
$con = mysqli_connect("localhost", "root", "password", "dbName");
$query = 'SELECT username, password FROM users';
if(mysqli_connect_errno() > 0)
{
echo 'Failed to connect to database.';
break;
}
else
{
$result = mysqli_query($con, $query);
while(($row = mysqli_fetch_row($result)) != null)
{
$query = 'UPDATE users SET password=\''
. hashSpecial($row['password']) . '\' WHERE username=\''
. $row['username'] . '\'';
$r2 = mysqli_query($con, $query);
}
}
}
?>
Related
As part of a job I want to update a database using a form. Since the database is large and is used by many users, I hope that this manipulation is at least secure for more safety.
HTML script :
<form action="http://localhost/modifier_infos_signaletique.php" method=POST >
<div class="id_sign">
<h5>Id "Signalétique" :</h5>
<input type="text" name="id_sign" id="id_sign"/><br>
</div>
<h5>Infos "Signalétique" : </h5>
<input class="comment" type="text" id="maj_infos" name="maj_infos" required maxlength='140'/><br>
<input type="submit" value="Submit" />
</form>
PHP script:
<?php
$user = 'xxxx';
$pass = 'xxxx';
try{
$dbconn = new PDO('pgsql:host=localhost;port=5432;dbname=xxxx',$user, $pass);
$dbconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$maj = $_POST['maj_infos'];
$id = $_POST['id_sign'];
$query = $dbconn->prepare("UPDATE signaletique SET infos = ':infos' WHERE id = ':id'");
$query->bindParam(':infos', $maj, PDO::PARAM_STR);
$query->bindParam(':id', $id, PDO::PARAM_INT);
$query->execute();
echo 'Données mises à jour';
}
catch(PDOException $e){
echo "Erreur : " . $e->getMessage();
}
?>
However, when I use this script this error appears:
**Erreur : SQLSTATE[HY093]: Invalid parameter number: :infos **
The error would be due to the parameter used for the bindParam function.
However, I have in the properties of my PostgreSQL database, info in "character varying". I tried to change this parameter to "text", but the error remains the same.
Forgive me for this question but I am new to PHP and my SQL skills are thin since I use pgAdmin and its tools a lot to build and interact with my databases.
Here is a screenshot of my database :
The info parameter is in "text" on the screenshot but basic this property was in "character varying" (140).
Thank you for your help.
In your query string you put single quotes around your placeholders. This makes them strings, not placeholders. You do not need quotes when using placeholders.
This should work:
$query = $dbconn->prepare("UPDATE signaletique SET infos = :infos WHERE id = :id");
See https://stackoverflow.com/questions/10966251/sqlstatehy093-invalid-parameter-number-parameter-was-not-defined for more information.
I am creating a simple perl script to create a web page to register users. This is just a learning program for me. It is very simple. I will display a page on the browser. The user enters name, user name, and password. After the user presses submit, I will check the user name against the database. If the user name exists in the database, I just want to display an error and bring up the register page again. I am using the cgi->redirect function. I am not sure if that is how I should use the redirection function. It does not work like I thought. It display "The document has moved here". Please point me to the right way. Thanks.
Here is the scripts
registeruser.pl
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print <<PAGE;
<html>
<head>
<link rel="stylesheet" type="text/css" href="tracker.css"/>
</head>
<body>
<div id="header">
<h1> Register New User</h1>
</div>
<div id="content">
<form action="adduser.pl" method="POST">
<b>Name:</b> <input type="text" name="name"><br>
<b>UserName:</b> <input type="text" name="username"><br>
<b>Password:</b> <input type="password" name="password"><br>
<input type="submit">
</div>
</body>
<html>
PAGE
adduser.pl
#!/usr/bin/perl
use CGI;
use DBI;
$cgiObj = CGI->new;
print $cgiObj->header ('text/html');
# get post data
$newUser = $cgiObj->param('username');
$newName = $cgiObj->param('name');
$newPass = $cgiObj->param('password');
# set up sql connection
$param = 'DBI:mysql:Tracker:localhost';
$user = 'madison';
$pass = 'qwerty';
$connect = DBI->connect ($param, $user, $pass);
$sql = 'select user from users where user = "' . $newUser . '"';
$query = $connect->prepare ($sql);
$query->execute;
$found = 0;
while (#row = $query->fetchrow_array)
{
$found = 1;
}
if ($found == 0)
{
# no user found add new user
$sql = 'insert into users (user, name, passwd) values (?, ?, ?)';
$insert = $connect->prepare ($sql);
$insert->execute ($newUser, $newName, $newPass);
}
else
{
# user already exists, get new user name
# What do I do here ????
print $cgiObj->redirect ("registerusr.pl");
}
One thing to look out for, SQL Injection. For an illustrated example, Little Bobby Tables.
As it stands your code is inescure, and can allow people to do bad things to your database. DBI provides placeholders as a secure way of querying a database with user input. Example http://bobby-tables.com/perl.html
Also, in this day and age even the CGI module warns you not to use it:
The rational for this decision is that CGI.pm is no longer considered good practice for developing web applications, including quick prototyping and small web scripts. There are far better, cleaner, quicker, easier, safer, more scalable, more extensible, more modern alternatives available at this point in time. These will be documented with CGI::Alternatives.
I suggest you use Dancer to make your life easier.
Three things
Include use strict; and use warnings; in EVERY perl script. No exceptions.
This is the #1 thing that you can do to be a better perl programmer. It will save you an incalculable amount of time during both development and testing.
Don't use redirects to switch between form processing and form display
Keep your form display and form processing in the same script. This enables you to display error messages in the form and only move on to a new step upon a successfully processed form.
You simply need to test the request_method to determine if the form is needing to be processed or just displayed.
CGI works for learning perl, but look at CGI::Alternatives for live code.
The following is your form refactored with the first 2 guidelines in mind:
register.pl:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
my $q = CGI->new;
my $name = $q->param('name') // '';
my $username = $q->param('username') // '';
my $password = $q->param('password') // '';
# Process Form
my #errors;
if ( $q->request_method() eq 'POST' ) {
if ( $username =~ /^\s*$/ ) {
push #errors, "No username specified.";
}
if ( $password =~ /^\s*$/ ) {
push #errors, "No password specified.";
}
# Successful Processing
if ( !#errors ) {
# Obfuscate for display
$password =~ s/./*/g;
print $q->header();
print <<"END_PAGE";
<html>
<head><title>Success</title></head>
<body>
<p>Name = $name</p>
<p>Username = $username</p>
<p>Password = $password</p>
</body>
</html>
END_PAGE
exit;
}
}
# Display Form
print $q->header();
print <<"END_PAGE";
<html>
<head>
<link rel="stylesheet" type="text/css" href="tracker.css"/>
</head>
<body>
<div id="header">
<h1>Register New User</h1>
</div>
#{[ #errors ? join("\n", map "<p>Error: $_</p>", #errors) : '' ]}
<div id="content">
<form action="register.pl" method="POST">
<b>Name:</b> #{[ $q->textfield( -name => 'name' ) ]}<br>
<b>UserName:</b> #{[ $q->textfield( -name => 'username' ) ]}<br>
<b>Password:</b> #{[ $q->password_field( -name => 'password' ) ]}<br>
<input type="submit">
</div>
</body>
<html>
END_PAGE
__DATA__
I have a very slight problem where I am not able to figure out how to get my target filepath not submit to the mysql database when the field value is empty. Right now, if I leave the image field empty, it still submits the filepath ($folder) to the database. I would like for when the field is left empty, to not send the filepath to mysql.
Form.php
<form enctype="multipart/form-data" action="add.php" method="POST">
HAZARD: <input name="haz1" value="hazard1" type="text" /><br>
<input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
IMAGE: <input type="file" name="photo"><br>
<input type="submit" name="action" value="Load">
</form>
Add.php
<?php
$folder = "images/";
$target1 = $folder . basename( $_FILES['photo']['name']);
$photo = $target1;
require("../db.php");
$haz1 = $_POST['haz1'];
mysql_query("INSERT INTO testimg VALUES (null,'$haz1','$photo')") ;
move_uploaded_file($_FILES['photo']['tmp_name'], $target1);
?>
I've tried
if (isset($_POST['photo']) ? $_POST['photo'] : null) echo $target1 == null);
I've tried other ways of isset as well but doesn't seem to work. Is there any other way i can accomplish this? Appreciate any help please. Thank you!
(Just a note, I have removed excess code above just to keep it short. I am taking care of SQL injection)
I would strongly suggest JavaScript, then users do not need to reload the page if it is empty. The JavaScript will check if it is empty for you. If it is you can make it so they cannot submit at all.
function validateForm()
{
var x=document.forms["myForm"]["fname"].value;
if (x==null || x=="")
{
alert("First name must be filled out");
return false;
}
}
This is an example above, if you would like better walk through go here
JQuery has libraries that you can use to do fancy things if it is left blank, just search for JQuery form validation for more tools.
Hope this helps!
Try using the inbuild HTTP_POST_FILE in PHP:
if (isset($_FILES['photo']) ? $_FILES['photo'] : null)
You could wrap the mysql code inside of an if function too:
if (isset($_FILES['photo']) {
//Do mySQL processing in here
}
A couple of points:
Require is at the top of a PHP script. It's nicer to see all requires
first.
I have used an inline if statement to determine what to set $photo
(elimintating need for $target1)
I have also moved the apostrophes into the assignment of $photo as
returning 'null' comapred to null (without the quotation marks) is
very different in SQL.
If $photo is not null at the end of the script then it moves the
updated file.
Please see the corrected code below:
<?php
require("../db.php");
$folder = "images/";
$photo = (isset($_FILES['photo']) ? "'" . $folder . basename( $_FILES['photo']['name']) . "'" : null);
$haz1 = $_POST['haz1'];
mysql_query("INSERT INTO testimg VALUES (null,'$haz1',$photo)") ;
if ($photo != null) { move_uploaded_file($_FILES['photo']['tmp_name'], $photo); }
?>
I am working with Mojolicious web framework to build a small site. I am aiming for strong security. The first step is to secure login information mainly username and password. I want to implement the logic given by the asker of this post Username, Password, Salting, Encrypting, Hash - How does it all work? . The username and password must be at least salted and hashed in a user's browser before they are sent to Mojolicious web server over the internet. I think the best way is to use embedded perl to manipulate the form values and then reassign them so that when 'submit' button is pressed only salted and hashed username,passwords are received inside the controller: The logic in mojolicious would be like(copied from Mojolicious website. MyUsers.pm handles login validation on server and I will tweak it to handle salted and hashed strings.)
#!/usr/bin/env perl
use Mojolicious::Lite;
use lib 'lib';
use MyUsers;
# Helper to lazy initialize and store our model object
helper users => sub { state $users = MyUsers->new };
# /?user=sri&pass=secr3t
any '/' => sub {
my $self = shift;
$self->render('login');
};
any '/' => sub {
my $self = shift;
$self->render('login');
};
any 'check_login' => sub {
my $self = shift;
# Query parameters
my $user = $self->param('user') || '';
my $pass = $self->param('pass') || '';
# Check password
return $self->render(text => "Welcome $user.")
if $self->users->check($user, $pass);
# Failed
$self->render(text => 'Wrong username or password.');
};
app->start;
__DATA__
## login.html.ep
% title 'Login Page.';
<form name="input" action="check_login" method="post">
User: <input type="text" name="user"><div>
Pass: <input type="password" name="pass"><div>
<!-- DO SOMETHING HERE to salt and hash $user and $pass before post -->
<input type="submit" value="Submit">
</form>
Finally got the solution in this excellent article link. However please be aware that there are many javascript md5 libraries. By mistake I downloaded a different md5 library than the one mentioned in the article. I wasted lot of time figuring out that the hash function did not work because I had a different md5 library. The article uses md5 lib from this link
I'm trying to create a custom module and I'm trying to get MY SQL access.
But i keep getting
mysql_query() [function.mysql-query]: Access denied for user
'scripts'#'localhost' (using password: NO) in
/home/scripts/public_html/crm/modules/PcPal/book-engineer.php on line
14
How do I access the data on the database when making a sugar module?
<?php if(!defined('sugarEntry') || !sugarEntry) die ('Not A valid Entry point'); ?>
<h2>Book an Engineer</h2>
<form method="POST" >
Search Last Name : <input type="text" name="frm_last_name_search" value="<?php echo $_POST['frm_last_name_search']; ?>" />
<input type="submit" value="Search"/>
</form>
<?php
$sql = 'SELECT first_name, last_name, primary_address_street FROM contacts WHERE last_name = \''.$_POST['frm_last_name_search'].'\'';
$results = mysql_query($sql);
while($this_result = mysql_fetch_array($result))
{
print_r($this_result);
}
?>
You should look into using the bean methods for very common queries like this, as it's easier and more portable.
http://developers.sugarcrm.com/wordpress/2012/03/23/howto-using-the-bean-instead-of-sql-all-the-time/
Use the global object $db for doing the database actions.
If you have the module bean eg: $bean = new Contact();, you can use $bean->db instead of global $db.
Also while fetching from a table always use deleted = 0, as deleted items are marked as 1.
global $db;
$sql = "SELECT first_name, last_name, primary_address_street FROM contacts
WHERE last_name = '{$db->quote($_POST['frm_last_name_search']}' AND deleted = 0";
$rs = $db->query($sql);
while($row = $db->fetchByAssoc($rs))
{
print_r($row);
}