GET vs. POST Best Practices

17,357

Solution 1

In general it's not a good idea to have a GET request that modifies the system state somehow, like deleting an item.

You could have your form look like this:

<form action='item.php' method='POST' id='form'>
    <input type='hidden' name='action' value='delete' />
    <input type='hidden' name='id' value='{item_id}' />
    <a href="" onclick="document.getElementById('form').submit(); return false;">Delete item</a>
</form>

Solution 2

Please use POST for anything that modifies persistent state in the database. You don't want crawlers visiting your delete links!
Have a read at Architecture of the World Wide Web, Volume One and URIs, Addressability, and the use of HTTP GET and POST by W3C.

Edit: Sometimes though you need to use GET. For example membership activation URLs which are sent in emails are GET and need to somehow modify the database.

Solution 3

You should never change anything in your database (other than logging information or other ephemeral data) from a GET request. The issue is that there is various web spidering software, web accelerators, anti-virus programs, and the like, that will perform a GET request on every URL they find; you would not want them to delete items automatically when they do so. GET is also vulnerable to cross-site request forgery; if an attacker makes one of your users click on a link that performs a bad action (for instance, creating a tinyurl that redirects to a delete URL), then they can trick the user into using their permissions to delete something without realizing it.

Yes, you will need a form that you submit to create a POST request. The other option is to use JavaScript and XMLHttpRequest, but that wont work for users who have JavaScript disabled.

You should also ensure that once you have accepted the data from the POST request, instead of returning a new page in response to that request, you should redirect the user to a page accessed by a GET request. This way, they will not accidentally re-send the POST request if they hit reload, or hit their back button later in their browsing session.

Solution 4

You don't want to use Get because of the REST principle of not allowing Gets to change the state of the system. Unless you like search engines to delete all your content.

You won't need a form for each item; you can use one method=post form around the list with a delete_{id} input type=submit. Or, more cleverly, <input type=submit name="delete_item" value="{id}">. Names are allowed on submit buttons.

Per your question in the comments, <input type=submit name="action_{id}" value="Delete"> might work better, though it suffers from some issues that would work badly for localized sites. You can always revert to a HTML Button for a little more control over the presentation. It acts like a submit button by default.

The fact that you may get extra, unwanted information in the submission is mitigated by the average-case of sending back a much larger page than necessary with your proposed form-per-item solution, when you're just viewing the list. You can always use javascript to substitute the behavior of the plain-old-html form with a smarter version for javascript-capable clients.

If you're going to link to a "Get" for deletion, you should return a confirmation page with that Get that actually does a post upon confirmation.

Solution 5

POST is not a protection from all malicious behavior as some people have implied. Malicious users can still create links (that contain javascript to do the POST) and cause the same cross-site scripting problems as with GET. (<a href="javascript:function () {...}"/>)

That said, all the other reasons for using POST over GET apply (crawlers and the like).

Share:
17,357
GeekJock
Author by

GeekJock

Updated on June 26, 2022

Comments

  • GeekJock
    GeekJock almost 2 years

    For my web application (PHP/MYSQL), I show a list of items and a link on each row to delete the item. Right now, the link is

    <a href='item.php?id=3&action=delete'>Delete Item</a>
    

    If I wanted to use POST instead... how would I do it (this is a dynamically generated list)? Can I send POST data without the use of a form?

    Or, for every item, would I have to do:

    <form action='item.php?id={$item_id}' method='POST'>
        <input type='hidden' name='action' value='delete'>
        <input type='submit' value='delete item'>
    </form>
    

    and style the submit button to look like the original link?

    I am not familiar with php CURL or REST, would they help address this issue?