I've got a page on my website where users can send me a message by giving their email, name, and a message. On the front end (JS) I do some basic verification, make sure the email is formatted like an email, make sure the other boxes aren't blank, and then I send it to PHP by GET.
Now I'm aware people can do some pretty sneaky stuff by injecting malicious code into PHP. What precautions should I be taking? When I was working with MySQL, I would escape it using the mysqli escape function. What should I be doing here?
Here's my script right now:
<?php
if(!isset($_GET["message"]) || !isset($_GET["name"]) || !isset($_GET["email"])){
echo "Check all the fields are correctly filled in and try again!";
die();
}
$email = $_GET["email"];
$message = $_GET["message"];
$name = $_GET["name"];
if($email == ""|| $message == "" || $name == ""){
echo "Check all the fields are correctly filled in and try again!";
die();
}
$message = wordwrap($message, 70);
mail("email#email.com","A Message From " . $name,$message,"From: $email\n");
echo "success";
?>
A very basic way is that you can declare a variable (for example $pattern)and store regular expressions (like patterns used commonly in attacks) in it, then use preg_match($pattern, $valueFromYourForm) method to see if any of the passed values matches any of those expressions and then you can stop the execution.
Related
my IF statements in this code are working, but the ELSE statement NEVER processes...and I am not sure why....in fact all of the code processes up until the ELSE statement, and the captua works properly too, if the captcha is right, the user gets a positive message and the data is posted to the database. If the captcha is wrong, no information is posted, but no message is given either..please help:
if(isset($_POST["captcha"]))
if($_SESSION["captcha"] == strtolower($_POST["captcha"]))
if(mysql_query($sql)) {
echo "<script type='text/javascript'>alert('submitted successfully, The records manager will provide you with your record within 3 days!')</script>";
//mail('joe.blow#idaho.com', 'SRRS - New Records Await Processing', 'SRRS - There are new records for processing in the SRRS System' );
//$to = 'joe.blow2#idaho.com' . ', ';
//$to .= $email;
$to = "joe.blow3#idaho.com";
$subject = "SRRS NOTIFICATION - New Student Record Await Processing";
$message = "New Student Record Requests have been submitted and Await Processing";
$from = "joe.blow#idaho.com";
$headers = "From:" . $from;
mail($to,$subject,$message,$headers);
echo "<script type='text/javascript'>alert('An Email Has to sent from the SRRS Records Management System to the Records Management Administrator for Processing.')</script>";
//Mail the user
$to = $email;
$subject = "SRRS NOTIFICATION - Your new record request has been submitted.";
$message = "SRRS - Your new record request for $givenname, $legname has been submitted, It will be procssed within 3 working days";
$from = "joe.blow#idaho.com";
$headers = "From:" . $from;
mail($to,$subject,$message,$headers);
}
else
{
echo "<script type='text/javascript'>alert('Human Verification not entered properly!')</script>";
}
The problem is that your output for "human verification" being incorrect is the else statement for your SQL query rather than the if statement before that which does the captcha comparison.
Condensed version of what you're doing:
if(isset($_POST["captcha"]))
if($_SESSION["captcha"] == strtolower($_POST["captcha"]))
if(mysql_query($sql)) {
// do stuff
} else {
// output CAPTCHA ERROR! <-- wrong place
}
Change where your statement is:
if(isset($_POST["captcha"])) {
if($_SESSION["captcha"] == strtolower($_POST["captcha"])) {
if(mysql_query($sql)) {
// do stuff
} else {
// CAPTCHA was fine, but the SQL query failed.
}
} else {
echo "<script type='text/javascript'>alert('Human Verification not entered properly!')</script>";
}
}
Note: While using curly brackets for control structures are not necessary when you only have one statement following it (an if block counts as one statement), it's far better for readability if you include them (so I've added them for you).
Looking forward: there are better ways to write your code than lots of nested if statements. You should try working on a structure that catches and handles errors as they happen, instead of wrapping large blocks of code in if statements and dealing with the alternative at the end. Try something like this:
if(!isset($_POST['captcha']) || $_SESSION['captcha'] != strtolower($_POST['captcha'])) {
echo "<script type='text/javascript'>alert('Human Verification not entered properly!')</script>";
exit; // kill the rest of the execution
}
if(!mysql_query($sql)) {
// SQL query failed, output an error
exit; // kill the rest of the execution
}
// Everything's fine, do the rest of your stuff here.
This could be further optimised by using functions and returning false instead of exit from various levels of functions that you call whenever you find an error.
Lastly, I'd suggest that outputting Javascript like that with an alert is probably not the best way to be doing this. You should have a kind of structure where the script/function that performs the task returns a boolean result (true/false) representing whether everything has gone smoothly, perhaps with an accompanying error message to describe it, and you should have a separate script/function that deals with the presentation of that result. An simple example here would be setting the result and message to the session and redirecting the user with PHP to a page that presents the results, instead of using a script tag with an alert.
While I'm at it too - mysql_* functions are deprecated. You should use mysqli_* or PDO instead.
I understand this has been discussed before but since this post in late 2010 and other discussions around that time when issues were raised - Does FILTER_VALIDATE_EMAIL make a string safe for insertion in database? - I have tried some of the situations described, such as using single quotes and the ` characters in an email form where I am using FILTER_VALIDATE_EMAIL and it has blocked them from being entered into the database.
Have recent releases of PHP fixed earlier issues and is it safe?
I'm tempted to also use mysql_real_escape_string(), presumably the two functions can be used in parallel without any conflict?
Here is the mailing list code that I am using to put addresses into the database
<?php
// connects the database access information this file
include("mailing_list_include.php");
// the following code relates to mailing list signups only
if (($_POST) && ($_POST["action"] == "unsub")) {
// trying to ubsubscribe; validate email addresses
if ($_POST["email"] == "") {
header("Location: mailing_list_remove.php");
exit;
} else {
// connect to database
doDB();
// filtering out anything that isn't an email address
if ( filter_var(($_POST["email"]), FILTER_VALIDATE_EMAIL) == TRUE) {
echo '';
} else {
echo 'Invalid Email Address';
exit;
}
// check that email is in the database
emailChecker($_POST["email"]);
// get number of results and do action
if (mysqli_num_rows($check_res) < 1) {
// free result
mysqli_free_result($check_res);
// print failure message
$display_block = "We couldn't find ".$_POST["email"].". No action has therefore been taken.";
} else {
// get value of ID from result
while ($row = mysqli_fetch_array($check_res)) {
$id = $row["id"];
}
// unsubscribe the address
$del_sql = "DELETE FROM subscribers
WHERE id = '".$id."'";
$del_res = mysqli_query($mysqli, $del_sql)
or die(mysql_error($mysqli));
$display_block = " Your email address, ".$_POST["email"].", is unsubscribed!";
}
mysqli_close($mysqli);
}
}
?>
<html>
<?php echo "$display_block";?>
</html>
The filter_var flag FILTER_VALIDATE_EMAIL will do what it says = Validate value as e-mail, meaning if its not an email it will return false.
You might be looking for FILTER_SANITIZE_EMAIL which will (Remove all characters, except letters, digits and !#$%&'*+-/=?^_`{|}~#.[] )
or
FILTER_SANITIZE_STRING will Strip tags, optionally strip or encode special characters.
Tho I don't recommend w3schools it has a list of filter_var flags http://www.w3schools.com/php/php_ref_filter.asp
Also as others have said, use PDO's prepared query's tobe safe, you can find a great pdo example here: http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html#10 which will explain a few things and there is also a simple pdo CRUD (Create Retrieve Update Delete) class here: http://www.phpro.org/classes/PDO-CRUD.html
good luck...
Although the item is successfully added to the database, I'm not sure that I'm executing the mysql_real_escape_string() function correctly and, thus, getting the error. Any help is appreciated.
Success!
Warning: array_map() [function.array-map]: Argument #2 should be an array in /home/site4/public_html/lab/mailing_list_dev_1-0/mailing_list_add.php on line 32
Thanks for signing up!
Here's the code in question...
<?php
// connects the database access information this file
include("mailing_list_include.php");
// the following code relates to mailing list signups only
if (($_POST) && ($_POST["action"] == "sub")) {
if ($_POST["email"] == "") {
header("Location: mailing_list_add.php");
exit;
} else {
// connect to database
doDB();
// filtering out anything that isn't an email address
if ( filter_var(($_POST["email"]), FILTER_VALIDATE_EMAIL) == TRUE) {
echo 'Success!';
} else {
echo 'Invalid Email Address';
exit;
}
// check that the email is in the database
emailChecker($_POST["email"]);
// get number of results and do action
if (mysqli_num_rows($check_res) < 1) {
// free result
mysqli_free_result($check_res);
// cleans all input variables at once
$email = array_map("mysqli_real_escape_string", ($_POST["email"]));
// add record
$add_sql = "INSERT INTO subscribers (email)
VALUES('".$_POST["email"]."')";
$add_res = mysqli_query($mysqli, $add_sql)
or die(mysqli_error($mysqli));
$display_block = "<p>Thanks for signing up!</p>";
// close connection to mysql
mysqli_close($mysqli);
} else {
// print failure message
$display_block = "You're email address, ".$_POST["email"].", is already subscribed.";
}
}
}
?>
<html>
<?php echo "$display_block";?>
</html>
You're treating $_POST['email'] as an array, which it probably ins't.
If you only intended to escape email, do
$email = mysqli_real_escape_string($dbConn, $_POST['email']);
Then in your INSERT statement, use the escaped $email instead of $_POST['email']
$add_sql = "INSERT INTO subscribers (email) VALUES('$email')";
array_map() is meant for arrays. If all you have is a single value then just call the function directly.
There is at least one bug, here:
// Does not work because $_POST["email"] is a string, not an array
$email = array_map("mysqli_real_escape_string", ($_POST["email"]));
This looks like something you adapted from code that was working, but right now it's broken. You probably wanted something like this:
$post = array_map("mysqli_real_escape_string", $_POST["email"]);
after which you can use $post["email"] safely, as it has been escaped.
Of course escaping everything inside $_POST is possibly not the best way to go about this. There's still the mundane but spot-on way to consider:
$email = mysqli_real_escape_string($_POST['email']);
This is apparently not mysqli_real_escape_string problem but array_map() problem. Or rather misuse of the latter one.
However, you will face mysqli_real_escape_string() problem as soon as you solves this one.
To solve this latter your doDB() function have to return connection id, which you have to use with every mysqli_* function.
$conn = doDB();
$email = mysqli_real_escape_string($conn,$_POST["email"]);
thus you will have all your [listed] problems solved but I believe that emailChecker will may cause the same kind of problem of inexistent $check_res variable. Instea d of which such a function apparently have to return just a boolean and used like
if (!emailChecker($_POST["email"])) {
following is my script for send email inquiry.. the recipient email address was stored in a db called users.. this script will not work properly.. i think the problem is recipient email section.. because when i used a email address instead of $user it will work..
thanx help me
<?php
$refno = $HTTP_POST_VARS['refno'];
$proid = $HTTP_POST_VARS['proid'];
$name = $HTTP_POST_VARS['name'];
$email = $HTTP_POST_VARS['email'];
$msg = $HTTP_POST_VARS['msg'];
//connect db and find email address related to id
include 'db_connector.php';
$id=$HTTP_POST_VARS['id'];
$query=mysql_query("SELECT user_email FROM users WHERE id='".$id."'");
$cont=mysql_fetch_array($query);
$user=$cont['user_email'];
// recipient name
$recipientname = "'".$name."'";
// recipient email
$recipientemail = $user ;
// subject of the email sent to you
$subject = "Inquiry for your advertisement No. (".$refno.")";
// send an autoresponse to the user?
$autoresponse = "no";
// subject of autoresponse
$autosubject = "Thank you for your inquiry!";
// autoresponse message
$automessage = "Thank you for your inquiry.! We'll get back to you shortly.
";
// END OF NECESSARY MODIFICATIONS
$message = "reference number : $refno
$msg
From $name $email
---";
// send mail and print success message
mail($recipientemail,"$subject","$message","From: $recipientname <$email>");
if($autoresponse == "yes") {
$autosubject = stripslashes($autosubject);
$automessage = stripslashes($automessage);
mail($email,"$autosubject","$automessage","From: $recipientname <$recipientemail>");
}
header("Location:index.php");
exit;
?>
First of all, your query is SQL injectable. Never ever pass a variable coming from a POST request directly into an SQL query. Use mysql_real_escape().
As to your bug: it seems that $user does not contain a valid e-mail address. so, the Mysql query is not returning an e-mail address.
Use $_POST rather than $HTTP_POST_VARS.
Switch on error reporting by prepending these two lines to your PHP code:
PHP code:
error_reporting(E_ALL);
ini_set('display_errors','1');
Run your script again. Do you get any notices or warnings?
If not, try to display your query, by adding
die($query);
just before the line that has the mysql_query command, and then run the query manually (e.g. using PhpMyAdmin or MySQL Query Browser) to see if you are actually getting a result that looks like an e-mail address.
Debug your PHP program.
Check out :
If the variables contain the supposed values.
Query is okay and returns result.
Proper header is set with mail function.
etc.
PHP manual have a good example to send mail.
Do not use $HTTP_POST_VARS['name']; it is deprecated use $_POST instead.
hey guys thanx for the help.. i found the error done in my inquiry form.. the id filed hidden outside of the form tag.. therefore the id value will not passed to the sendinq.php. i change it thank now the sendmail option work properly
I was wondering how do I allow only one email address? Also how can I only check for the # sign in the email address to validate the email?
Here is my PHP code.
if (isset($_GET['email']) && strlen($_GET['email']) <= 255) {
$email = mysqli_real_escape_string($mysqli, strip_tags($_GET['email']));
} else if($_GET['email'] && strlen($_GET['email']) >= 256) {
echo '<p>Your email cannot exceed 255 characters!</p>';
}
Don't.
Use a completely RFC-compliant validator instead, followed up with an actual mail to the address. Truly, sending a mail to the address is the only real way to make sure it's a legitimate email address.
PHP has filter_var which can be used like this:
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
if (strpos($email, "#") === true) {
// VALID
}
}
This is a simple way to check if common address are valid (and will not allow obvious fakes) however, this doesn't make sure your email address is valid according to the RFC 822, RFC 2822, or RFC 3696.
I would also like to point this out. That will validate an email address according to the proper RFCs.
If this is a form, you can use input type="email" in your form. It is part of HTML5, so it isn't implemented in all browsers yet.
This won't serve the full purpose, but it will prevent a single page load for obvious mistakes (forgetting # or .com) to help a little. Browsers which implement it prevent you from submitting the form if it's invalid; also, Apple devices will utilize a special keyboard for that entry with "#" and ".com" present.
(Just an extra piece of info, since I don't know your whole situation.)
how do I allow only one email address?
Run SELECT query to see if there is such an email already.
how can I only check for the # sign in the email
strpos would be enough.
Though it would be a good idea to confirm email address by sending a letter to that address, you know.
Also you have a few things to correct in your code.
your else if statement is not necessary, there should be just else
and mysqli_real_escape_string shouldn't be in the validation section. It is database related function, not validation one.
And if it's registration form, it should use POST method
so, smth like this
$err = array();
if (empty($_POST['email']) $err['email'] = "email cannot be empty";
if (strlen($_POST['email']) >= 256) $err['email'] = "email is too long";
if (!strpos("#",$_POST['email'])) $err['email'] = "malformed email";
$query = "SELECT 1 FROM members WHERE email ='".
mysqli_real_escape_string($mysqli, $_POST['email'])."'";
$res = mysqli_query($mysqli, $query) or trigger_error(mysqli_error($mysqli).$query);
if (mysqli_num_rows($res)) $err['email']="email already present";
//other validations as well
if (!$err) {
//escape all the data.
//run your insert query.
header("Location: ".$_SERVER['REQUEST_URI']);
exit;
} else {
foreach($_POST as $key => $value) {
$_FORM[$key]=htmlspecialchars($value,ENT_QUOTES);
}
include 'form.php';
}
try using regex expression for it... you can find patterns in google
on eg:
if (!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email)){
echo "<center>Invalid email</center>";
}else{
echo "<center>Valid Email</center>";}
}
Edited for preg_match:
if (!preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i", $email)){
echo "<center>Invalid email</center>";
}else{
echo "<center>Valid Email</center>";
}