简体   繁体   中英

How do I use $_GET[“id”] securely with PDO query?

I'm trying to get the id of a page from the url and use it to retrieve the information from the database. I want to ensure that the id is an integer with a length less than 4 and redirect to a parent page if not.

if(isset($_GET["id"])) {
    $id = (int) $_GET["id"];
    // If id is longer than 4 redirect
    if(strlen($id) > 4) {
        header("Location: /parent.php");
        exit;
    }
    try {
        $sth = $dbh -> prepare("SELECT id, title, etc, FROM table WHERE id = :id");
        $sth -> bindParam(':id', $id, PDO::PARAM_INT);
        $sth -> execute();
    } catch(PDOException $e) {
        // print $e -> getMessage();
        echo "Error";
        exit;
    }
    $feature = $sth -> fetch(PDO::FETCH_ASSOC);
    // If query result is empty redirect
    if($feature == false) {
        header("Location: /parent.php");
        exit;
    }
    $sth = null;
} else { // If id isn't set redirect
    header("Location: /parent.php");
    exit;
}

Is the way I'm doing this secure/correct? I'm still getting to grips with this sort of thing so am second guessing myself.

Also, it seems to work as I intended except when the id is set to something like 123abc (child.php?id=123abc) which it interprets as 123 and still loads the information for id 123. Because I'm casting the type is it just ignoring the abc part? Should I be concerned that it still loads and doesn't redirect to parent?

You could use input filtering instead to make sure the passed identifier is indeed an integer; whether it's bigger than 9999 shouldn't matter, but perhaps testing for a positive integer is a good idea:

if (($id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)) !== false && $id > 0) {
    // id was passed and it's a valid integer
} else {
    // evil request, die die
}

The use of prepared statements already mitigates a potential SQL injection attack, so the rest of your code doesn't have to change, though I would personally try to make a single failure flow instead of four separate (but nearly identical) ones.

Yes, by casting the input to integer, you have circumvented any sql injection attacks. And by using bind variables you have prevented sql injection attacks again. :)

And that you use strlen on an int is a little ugly, so I would advise to check $id > 9999. Though you will probably not notice the difference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM