2

I'm having an issue where my PHP mail code runs every night at like 11:30pm. I'm sure no one is clicking the form submission button. The email contents are empty.

In my PHP mail code, I add the contents to a database just in case the email does not go through, then send the email as well.

Thanks

Form:

<form action="background/mail.php" method="POST">
    <div class="row">
        <div class="six columns">
            <label>Your email</label>
            <input class="u-full-width" type="email" placeholder="example@validmail.com" name="email">
        </div>
        <div class="six columns">
            <label>Reason for contacting</label>
            <select class="u-full-width" name="reason">
                <option>Inquiry</option>
                <option>Order</option>
                <option>Other</option>
            </select>
        </div>
    </div>
    <div class="row">
        <div class="u-full-width">
            <label>Message</label>
            <textarea class="u-full-width" placeholder="Enter message here" name="message"></textarea>
          <input class="button-primary" type="submit" value="Submit">
        </div>
    </div>
</form>

mail.php:

<?php
    $to = "support@website.ca";
    $reason = "CUSTOMER MAIL: " . $_POST['reason'];
    $email = $_post['email'];
    $msg = $_POST['message'] . "\nemail: " . $email;
    $header = "MIME-Version: 1.0\r\n";
    $header.= "Content-type: text/html\r\n";
    $header.= "From: " . $email . "\r\n";
    $header.= "Reply-to: support@website.ca\r\n" . "X-Mailer: PHP/" . phpversion();

    require("login.php");

    $sql = "INSERT INTO emails (email, message, reason) VALUES ('$email','$msg','$reason')";

    if($conn->query($sql) === TRUE){
        mail($to,$reason,$msg, $header);
        echo "Added to database, mail sent.";
    } else {
        echo "Error: " . $sql . "<br>" . $conn->error;
    }

    $conn->close();

?>
Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
Ishaan
  • 707
  • 1
  • 7
  • 16
  • Did you ever set up a CRON or something? – gen_Eric Apr 27 '16 at 17:14
  • 2
    if you do not have any cron jobs set to run the script then try adding a capcha maybe? – Nick Surmanidze Apr 27 '16 at 17:14
  • Do you have a cron job set up? How are you so sure that no one is submitting your form at that time? – Nick Apr 27 '16 at 17:15
  • 1
    P.S. Please use *prepared statements* to prevent against SQL injection. – gen_Eric Apr 27 '16 at 17:15
  • @ishyfishy it seems any cron is set where mail.php is called from that schedule. – naf4me Apr 27 '16 at 17:15
  • 1
    Either what was said, or there's a bot out there who's got it out for you. Yet, what you're NOT doing, is checking if any of the POSTs are empty or not, not using an `isset()` against a submit button and this is wrong `$_post` that needs to be in uppercase. – Funk Forty Niner Apr 27 '16 at 17:15
  • 3
    Check you access logs for that time. and look for POST requests to `"background/mail.php` – Dan Apr 27 '16 at 17:15
  • 1
    Could this happen from a search engine crawling his site? – David Wyly Apr 27 '16 at 17:17
  • Check your webserver logs to see what is happening at that time. – Eborbob Apr 27 '16 at 17:19
  • 2
    what @dan08 said makes a lot of sense. If you see many requests coming from the same or similar address like `123.456.789` or `123.456.780`, then setup something in `.htaccess` to block them or setup a white/blacklist in an array in your PHP before processing anything. I've done this before and used as an include. – Funk Forty Niner Apr 27 '16 at 17:20
  • Ok, so now it's your turn to interact here ;-) whats the score? – Funk Forty Niner Apr 27 '16 at 17:25
  • @everyone OK WOW <3 So many replies. I checked my access logs and I'm getting lots of hits from something called SiteLockSpider everyday between 11:30 and 11:50pm. I'm having the same problem as this guy. https://www.sitepoint.com/community/t/form-on-my-website-being-sent-automatically-every-night/61190. The IP from which the hits are being generated from is 184.154.139.17, I'll block it – Ishaan Apr 27 '16 at 17:27
  • @ishyfishy which a reply in there read as *"Thanks everybody for the help. Validation solves the problem."* as [I previously stated](http://stackoverflow.com/questions/36896399/php-mail-script-auto-runs-same-time-every-night#comment61357314_36896399) ;-) – Funk Forty Niner Apr 27 '16 at 17:29
  • @Fred-ii- yep! I'll do that :). Thanks for your suggestion – Ishaan Apr 27 '16 at 17:30
  • @ishyfishy You're welcome and as per [my other comment](http://stackoverflow.com/questions/36896399/php-mail-script-auto-runs-same-time-every-night#comment61357487_36896399) also ;-) works beautifully I might add. However, I occasionally need to add to my array, they just never stop *lol* – Funk Forty Niner Apr 27 '16 at 17:31

2 Answers2

2

Most likely someone is making POST requests directly to your mail script to send out emails. There are some non-fool-proof ways to stop this:

  1. Add some checking for the contents of the POST request. e.g. no empty body, valid email address, other logical checking. (you should be doing this anyway).

  2. Add an additional hidden field to your form that is empty. Confirm that it is empty in mail.php in order to proceed. The idea: crawlers try to fill all form fields, but a user won't fill in a hidden form field

  3. Add a hidden field and fill it with some value using JS and validate in mail.php. Crawlers cant use Javascript so the field will be empty (gotcha: will not work for users that disable JS).

Any of these can be circumvented, but they are trivial to implement and make things slightly more difficult for the crawler.

For true security there are more complex solutions. Maybe someone can outline those in an answer.

Dan
  • 10,614
  • 5
  • 24
  • 35
  • thanks for your answer. I have blocked the IP of the crawler that was the issue! You have some very great tips that I'll be implementing right now to prevent future problems like this. – Ishaan Apr 27 '16 at 17:37
  • Yea, keeping up with blacklisting IPs could become your part-time job. But is a valid counter-measure. – Dan Apr 27 '16 at 17:40
1

As I stated in comments in having fallen victim to a bot (or many bots); here is what I use to block out certain IP addresses and used as an include in every file.

You should also check for empty() fields and use an isset() against a submit button.

The following doesn't need the last 4th set, but you can always add to it, as it checks for anything following the 3rd set.

You can even narrow it down to using only 2 sets.

$ip = $_SERVER['REMOTE_ADDR'];

$nums = explode(".", $ip);

$if = "{$nums[0]}.{$nums[1]}.{$nums[2]}";

$blacklist = array(

"184.154.139", 
"123.4.111", 
"234.5.678"

);

if (in_array($if, $blacklist)) {

// echo "Rejected";

header("Location: http://www.example.com/");
exit;

}

else { 

// Run your other code to do the variable check, mail processing etc.
}

I.e.:

Name your submit button:

<input name="submit" class="button-primary" type="submit" value="Submit">

Then check if it's set and that none of the POST arrays are (not) empty:

if(isset($_POST['submit'])){

    if(!empty($_POST['reason']) && !empty($_POST['email'])){

        $reason = $_POST['reason'];
        $email  = $_POST['email'];

        // Run your executables in here

    }
}
  • Another effective method is to use a checkbox and to validate if it was checked or not.

Also as stated, your present code is open to SQL injection. Use prepared statements, or PDO with prepared statements.

Plus, that syntax error about $_post that I stated in comments, needs to be in uppercase $_POST as it's a superglobal.

Community
  • 1
  • 1
Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
  • 2
    thanks for your extremely detailed answer. I just have one question, after `$ip = $_SERVER['REMOTE_ADDR']`, why do you have to split it? Does `$_SERVER['REMOTE_ADDR']` return something other than just the ip of this format `xxx.xxx.xxx`? – Ishaan Apr 27 '16 at 18:05
  • @ishyfishy You're welcome. The reason being is that some of those (sneaky) bots tend to change their last sequence in their IP addresses, for example `123.456.789.111` to `123.456.789.123` or `123.456.789.000` type of thing. So here, we are blocking everything matching the 3rd to last sequence. – Funk Forty Niner Apr 27 '16 at 18:08
  • @ishyfishy To reply to your second question (that I forgot to answer), have a read here on PHP.net http://php.net/manual/en/reserved.variables.server.php You can probably modify it, but kind of suggest you don't, because you want to check on an IP address and not a domain. So the answer would be no; it only returns an IP address (for the server/person visiting your site). – Funk Forty Niner Apr 27 '16 at 18:19
  • @Fred-ii- What is the likelihood of blocking valid users with this approach? – Dan Apr 27 '16 at 18:22
  • @Fred-ii- Cool, that clears up all my doubts! I read the link you just provided and indeed `$_SERVER['REMOTE_ADDR']` can return ip in form `127.0.0.1`. I'll stick with the solution you've provided – Ishaan Apr 27 '16 at 18:22
  • @dan08 I'd say unlikely as bots don't (least I hope they don't) allow good/honest people be piggybacked on their IP. If they are, they're probably just as guilty and deserve to be kicked out *lol* - Yet, I never had complaints for valid users in the past/present. – Funk Forty Niner Apr 27 '16 at 18:23