This is a general question on password form validation and using a combination of uppercase, lowercase, numbers and characters used.
Research has showed that preg_match is required to validate the password (or whatever variable you use): (preg_match("/^.(?=.{8,})(?=.[0-9])(?=.[a-z])(?=.[A-Z]).*$/")
Though how would how would i integrate this into the if statement below? I've tried combining them using && though this seems to ignore the preg_match part. if(($pass == $pass2) && (preg_match("/^.(?=.{8,})(?=.[0-9])(?=.[a-z])(?=.[A-Z]).*$/"))
Any advice would be appreciated.
<?php
require "dbconn.php";
$username = ($_GET['username']);
$email = ($_GET['email']);
$pass = ($_GET['pwd1']);
$pass2 = ($_GET['pwd2']);
$USN = ($_GET['schoolnumber']);
$matching = 0;
if($pass == $pass2)
{
echo "<script type='text/javascript'> window.alert('Your details have been successfully registered, please proceed to login with your new credentials!')</script>";
echo '<script>javascript:window.close();</script>';
$query = "INSERT INTO customer VALUES ('".$username."','".$email."','".$pass."','face1.jpg','".$USN."','N')";
$results = mysql_query($query) or die (mysql_error());
$results1 = mysql_query($query1) or die (mysql_error());
}
else{
header('Location:register.php?matching=1');
}
?>
preg_match requires two arguments the pattern to look for and the string to test. Plus I'm not sure if the regular expression you are using would work anyway. Try something like.
$pattern = '/(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}/';
if (($pass1 == $pass2) && preg_match($pattern, $pass1)) {
...
}
You only need to match against one of the passwords because should ($pass1 == $pass2) fail then the preg_match isn't even preformed.
The regex above checks that the password is at least 8 characters long and contains at least one of each of lowercase, uppercase and a number
Related
The user can enter a password into a POST form and the code will search the wordlist $file for the password. If it finds the password in the wordlist, it will inform the user. This works 90% of the time for generic passwords like Banana123 and Brad101. However, if the user enters a password like BananaK123 the code will return nothing. Is there a way to make the code ignore the letter 'K' in the password BananaK123 so it just searches for Banana123 instead?
if ($_SERVER["REQUEST_METHOD"] == "POST") {
function dictionaryCheck() {
$file = file_get_contents("100k-most-used-passwords-NCSC.txt");
if(isset($_POST['dictionaryCheck'])){
$password = ($_POST['password']);
$password2 = preg_replace("/[^a-zA-Z]/", "", $password);
$pos = stristr($file, $password2);
if ($pos === false) {
echo "The dictionary word '$password2' was not found";
} else {
echo "The dictionary word '$password2' was found ";
echo " and exists at position $pos";
}
}
}
}
dictionaryCheck();
Try looking into similar_text(). You may want to reject strings that match a certain similarity.
https://www.php.net/manual/en/function.similar-text.php
This was just to answer your direct question. However, I would not suggest this way. ZXCVBN is a better solution. The reason I am saying this is that you will not be able to tell your users WHY you are rejecting that password. You may cause a lot of frustration.
I have been trying to implement a server-side validation of a POST value in PHP - the value should be either a valid email address or an 8-digit number.
What I've got so far is:
<?php
$username = $_POST["username"];
if (!filter_var($username, FILTER_VALIDATE_EMAIL) || second-condition-about-8-digit-number-here) {
header("Location: ../login-error/?&sessionid=$hash&securessl=true");
die();
}
?>
I'd love some guidance as to how to implement this. The input value should be either an email address OR an 8 digit number.
<?php
$username = $_POST["username"];
if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !preg_match('/^[0-9]{8}$/', $username)) {
header("Location: ../login-error/?&sessionid=$hash&securessl=true");
die();
}
?>
You need to use strlen to get the length of a string.
As you only care about digits then you could use this approach ..
$length = strlen(preg_replace("/[^0-9]/", '', $username));
That will set $length to be the number of characters exist in the string $username that are numeric.
I want that once the person enters their information for log in it brings them to home.php. my current code is this:
if (isset($_POST["user_login"]) && isset($_POST["password_login"])) {
$user_login = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["user_login"]);
$password_login = preg_replace('#[^A-Za-z0-9]#i', '', $_POST["password_login"]);
$md5password_login = md5($password_login);
$sql = mysql_query("SELECT id FROM users WHERE username='$user_login' AND password='$md5password_login_md5' AND closed='no' LIMIT 1");
$userCount = mysql_num_rows($sql);
if ($userCount == 1) {
while($row = mysql_fetch_array($sql)){
$id = $row["id"];
}
$_SESSION["id"] = $id;
$_SESSION["user_login"] = $user_login;
$_SESSION["password_login"] = $password_login;
header("location: home.php");
exit();
} else {
echo 'That Log In information is incorrect, please try again';
exit();
}
}
?>
I gather this is (hopefully) a testing script, or a way to learn. That's cool, but there's multiple things that I'd suggest you look into:
You're using mysql_* functions. These are now deprecated. It's suggested to use mysqli or PDO
You're using md5 for password storage. Please use password_hash and password_verify instead
Using regexes to validate data isn't a bad idea, and credit for using them. However, you might want to give the regex a quantifier so it matches more than just one character. Just put a + after your [^A-Za-z0-9] blocks
The main reason your header might not be working is that it is case sensitive, and should be a full URL. See the notes on the PHP manual page for header()
Have a look at PHP The Right Way. You're starting out well, but without guidance you're going down paths that'll be problematic later.
I am trying to make a script, that interact with mysql database and allows to find someone by username. But the problem is that it is not comparing characters. Means in my databse, user name is "abcd", in lowercase. But when I go to
localhost/ABCD or
localhost/Abcd or
localhost/ABcd or any upper or lowercase, it shows me same result. I want different result with different cases. I don't know what to use. I searched a lot and found preg_match function but don't know how to use. The function I created for this match from database is,
function CheckPnP($var){
$db = new mysqli ('localhost', 'root', '', 'database');
if($var){
if($result = $db->query("SELECT * FROM `view` WHERE `username` = '$var'")){
if($result->num_rows){
$rows = $result->fetch_assoc();
$_GET['username'] = $rows['username'];
$_GET['view'] = $rows['page'];
include $_SERVER['DOCUMENT_ROOT'].'/core/view.php';
return true;
}
}
}
}
and my view.php page codes are
<?php
#$view = $_GET['view'];
#$username = $_GET['username'];
if($view == 'profile'){
echo 'This is profile page.';
}
else if ($view == 'page'){
echo 'This is page.';
}
else if ($view){
header('Location: /');
}
else if (empty($view)){
echo 'this is view page123. ';
}
echo '<br>'.$username;
?>
view.php page's codes are temporary. I will change them soon but right now I need to match characters of username from database and I need exact character match.
Please help me.
I actually just found out about this a few weeks ago:
SELECT * FROM `your_table` WHERE BINARY `your_column` = 'VaLue';
SELECT * FROM `your_table` WHERE BINARY `your_column` = 'value';
SELECT * FROM `your_table` WHERE BINARY `your_column` = 'vaLue';
This would return different results depending on your query.
I suggest you do the above instead of in PHP.
About your second question:
There are a ton of things you can do to match characters in PHP. strcmp (case sensitive), ===, ==, strcasecmp (case insenstive)
Can you experts give me some thougths on this code? Some security hole i have missed?
Can you see any potential threats? Something i can do better?
I'm still learning :) Thanks
<?php
if (isset($_POST['username'])) {
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$password2 = mysql_real_escape_string($_POST['password2']);
$encrypted_password = md5($password);
// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);
// check if username is taken
$query = mysql_query("SELECT COUNT(*) FROM users WHERE username = '$username'");
if (mysql_result($query, 0) > 0) {
$reg_error[] = 0;
}
// make sure username only cosist of at least 3 letters, numbers or _ -
if (!preg_match('/^[a-zA-Z0-9_-]{3,}$/', $username)) {
$reg_error[] = 4;
}
// check for empty fields
if (empty($username) || empty($password) || empty($password2)) {
$reg_error[] = 2;
}
// check if the passwords match
if ($password != $password2) {
$reg_error[] = 3;
}
// save if error is unset
if (!isset($reg_error)) {
mysql_query("INSERT INTO users (username, password, registered, registration_ip)
VALUES('$username', '$encrypted_password', '".time()."', '".$_SERVER['SERVER_ADDR']."')");
$_SESSION['id'] = mysql_insert_id();
header('refresh: 3; url=/home');
}
}
?>
Login.php
if (isset($_POST['username'])) {
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$md5_password = md5($password);
$query = mysql_query("SELECT id FROM users WHERE username = '$username' and password = '$md5_password'");
if (mysql_num_rows($query) == 0) {
header("Location: ".$_SERVER['REQUEST_URI']."");
exit;
}
// set session
$_SESSION['id'] = mysql_result($query, 0, 'id');
header("Location: /");
exit;
You didn't salt the password.
Also, md5() is considered not strong enough for hashing passwords.
Use hash('sha256', $password) instead.
I assume you're serving this on https, though you don't mention whether you do -- if you're not, username and password travel on the open net in the clear, and that's definitely not very safe.
There's a race condition -- you check whether the username is taken, first, and only later do you insert it. You should use a transaction, a least, and ideally just try to insert (with the uniqueness constraint imposed by the database) and catch the error in case of duplicates. And, you should do this only after all other sanity checks, i.e. when you've convinced yourself that, apart from possible duplicates, the registration attempt is OK.
Little bobby tables will give you a lot of headaches since you do not check for username validity.
You need to salt the password.
This is placed in the wrong place. Move it up a few lines before the $_POST vars are used.
// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);
You are escaping the password fields for no reason. They are not being sent to the database. md5($password) is going to the database and it is not escaped.
EDIT: On the login side, you should be trimming anything you are trim on the registrations side.
Your error checking is out of order. I'd do the error checking in this order:
Check for empty fields
Check that the fields have valid values (filtering input)
Escape the fields with mysql_real_escape_string before using the fields in SQL
Check for the user in the SQL table
If you find an error don't continue with further checks. Guard each error check similar to your guard on the final INSERT statement.
You have no edits on the password fields besides using mysql_real_escape_string?
You should do mysql_connect before using mysql_real_escape_string. mysql_real_escape_string will use the connection to determine the character set of the connection. The character set will identify which characters to escape.
You should use parameters instead of building your sql dynamically. It will help prevent sql injection attacks. Little bobby tables will get you.