php secure comment logic? - php

Ok, this might be obvious but its not clicking quite yet. I am creating a forum/blog esque app.
I grab the posts from the database rather securely but commenting is beginning to be a little more difficult. (I could just be paranoid, right?).
How do I add a comment without exposing the id of the parent message? (like in a hidden form field or query string, or something).
I guess I am a bit paranoid that someone might go into the code with firebug or something and change the hidden form field value to something else before submitting. I guess I would have to make sure the user has permission to comment to that particular post/category?
Things to note :
The user is already logged in.
Its not a public post

I would recommend that you setup your database like so:
Comments
---------
id
encodedID
authorID
parentID
message
Then, for the form field have two hidden values, one will be the encodedID, and the second will be a hash that you make. I would recommend the hash to be:
<?php
$hash = sha1(md5($encodedID . $userID . $_SERVER['REMOTE_ADDR'] . "abc1234"));
?>
Then, when the user submits the form, validate that the hash is valid for the specific encodedID and user. Here is a brief code write up:
<?php
if(isset($_POST['submit']))
{
//Get the variables and all and sanitize the input of 'message'
if(sha1(md5($_POST['value1']. $userID . $_SERVER['REMOTE_ADDR'] . "abc1234")) == $_POST['value2'])
{
//User is valid.
}
else
{
//Invalid user.
//Document this.
}
}
$value1 = $encodedID; //Grab this from your database
$value2 = sha1(md5($value1 . $userID . $_SERVER['REMOTE_ADDR'] . "abc1234"));
?>
<form method="post" action="comment.php">
<input type="text" name="message" />
<input type="hidden" name="value1" value="<?php echo $value1; ?>" />
<input type="hidden" name="value2" value="<?php echo $value2; ?>" />
<input type="submit" name="submit" value="Comment" />
</form>
Edit: Just a small tip, but I would recommend that you change value1 and value2 to something abstract, don't call it encodedID or anything like that, just so that it confuses any users that will attempt to try and break it.
And yes md5 and sha1 are not completely secure, but for this case it will work since you want to be able to process the comments fast and efficiently.

That might be an overkill but if you really want to hide the post_id of the current message then you should consider using session. So instead of using something like this on your form:
<form action="/postcomment.php" method="post" >
<input name="post_id" type="hidden" value="123" />
<textarea name="message"></textarea>
</form>
Reduce it to something like this:
<?php $_SESSION['post_id'] = '123'; ?>
<form action="/postcomment.php" method="post" >
<textarea name="message"></textarea>
</form>
Of course this is "yucky" coding but at least you get the idea.
Oh, don't forget to validate EVERYTHING on postcomment.php. Also escape ALL string input values and make sure all numeric inouts are numbers indeed (multiply them by one?).
[EDIT: Due to insistent public demand, may I, if you please, amend the aforementioned:]
Instead of:
<?php $_SESSION['post_id'] = '123'; ?>
Generate a form id:
<?php $_SESSION['form_id'] = $_SESSION['user_id'].'_'.md5(time()); ?>
Then generate the unique post_id:
<?php $_SESSION[$_SESSION['form_id'].'_post_id'] = '123'; ?>
After submitting get the post_id:
<?php $post_id = $_SESSION[$_SESSION['form_id'].'_post_id']; ?>

you could assign the form an "id" as a hidden field and create a database table to track form ids and their associated post ids, that way when the form gets submitted you could check the post id in the db without ever sending it to the client based on the form id that is returned with the post

You're asking the wrong question here: instead of being concerned about the user getting some internal ID that means nothing outside your application, your primary concern should be about keeping them from doing anything unpleasant with it.
Imagine I just started sending POST requests to add a comment for every ID between 1 and 10,000. I'm sure to hit a real post sooner or later.
Rule #1 about writing secure web applications: Don't trust the user.
In other words, yes, you should check to make sure that they have permission to comment when you receive the results back from the from.

Related

update_options not updating wp_options table

I am making a form for the admin area of WordPress. Here is the code so far;
<form method="post" action=options.php">
<?php update_option('gpspl_options', $gpspl_options);?>
<input type="text" name="gpspl_options" value="$gpspl_options"/>
<input type="submit" value="Save Changes"/>
</form>
On the page in the admin area the text box is auto filled with "$gpspl_options". However when I add the text and hit submit it does not update the wp_options table in the database.
What am I missing?
You always call update_option() on whatever is stored in $gpspl_options. You never do anything with the posted value ($_POST['gpspl_options']). So the posted value never gets saved. If you want to save the posted value, you need something like this:
if (isset($_POST['gpspl_options'])) {
update_option('gpspl_options', $_POST['gpspl_options']);
}
As for the text field, you always initialize the text field to the literal string "$gpspl_options" (not the value of the variable $gpspl_options). To use the value, you need something like this:
<?php
$gpspl_options = isset($_POST['gpspl_options']) ? $_POST['gpspl_options'] : '';
?>
<input type="text" name="gpspl_options" value="<?php echo $gpspl_options; ?>"/>
You might want to read an introductory PHP tutorial covering variables, variable names, output, and so on.
That said, all this mixing of logic and output is not good practice. It's what Wordpress does and therefore kind of encourages, but that doesn't mean you should do it, too.

php make hidden fields tamper proof ?

I'm not wanting to use a framework when in this project there is only a single value that needs verifying, I want to make sure however that the method I'm using is reasonably safe and sane!
I have a $secret value set in an include that is outside the web root
the form looks like this ( $salt is a random integer a new one for each form)
<form name="deleteform" action="#" method="get">
<input type="hidden" name="check" value="<?=sha1($salt.$secret.$songid)?>"/>
<input type="hidden" name="songid" value="<?=$songid?>"/>
<input type="hidden" name="salt" value="<?=$salt?>"/>
<input type="hidden" name="action" value="delete"/>
<input type="submit" value="Delete"/></form>
when the form is returned I use the returned values for $salt $songid along with $secret to calculate a new sha1 and compare it to $check
if they are equal I assume that the returned $songid hasn't been tampered with
Using $_SESSIONS is the way to go. Even if you wanted to still do the tamper proof hidden field idea. To make it tamper proof you'd have to set the value on the server side after hitting submit. You could do this using jQuery's .preventDefault(), set the value of the hidden fields at that point, and then continue with the submission. But why do the extra step?
Just use sessions from the get go, eg:
session_start();
$_SESSION['name'] = value;
echo $_SESSION['name'];
$_SESSION is the way to go... the downside of your design is that one can still temper with the form by simply copy/pasting values.
Also, if they figure out what kind of check you are doing, there is absolutely nothing stopping them from putting in their own songid, computing their own sha1 hash and stuffing it into your check field.
General intro to sessions:
session_start();
$_SESSION['songid']=your song id;
and you are done... Now the songid value is stored on server, and nothing can tamper with it besides you... unless openSSL breaks again.

PHP 'Checkbox' Alternative when updating

I have a small problem with my PHP Code and as always, any help is hugely appreciated.
The code was originally designed by another person and I seem to have come across a problem that I can't fix.
The structure of the page is as follows:
A while loop to output the data, each of course, has a unique id.
A checkbox that must be ticked before pressing the 'update' button
(several update buttons present pending on how many rows are
returned.
This is what i'm confused on, he has designed it to they must tick the 'checkbox' before pressing update, otherwise, the script doesn't know which 'id' to update. Why is it like this?!
<?php
if($_POST['accept']){
if(!$_POST['check']){
echo "<div class='error_input'>Error! please tick box to confirm </div>";
}else{
$form_id=$_POST['fid'];
$customer=$_POST['customer'];
mysql_query("UPDATE job SET customer='$customer'WHERE f_id=$form_id ");
echo "<div class='form_ok'>Job has been updated.</div>";
}
?>
If I just comment out the check box, and the user clicks the 'accept' button, it doesn't work, so clearly the 'checkbox' is pointing to the unique ID of the row, but I can't see it?
<input type="checkbox" name="check" value="1" required/>
<input type="submit" name="accept" value="Accept Job">
My issue is, I want to be able to remove this annoying checkbox, and once the user has pressed 'accept' add the unique ID into a session, which I know can be done by:
$_SESSION['user_id'] = $user_id;
As they then get redirected to a pop-up box to which I need this unique ID to pull further data from the database.
I've had a go at implemented this:
<input type="submit" name="accept" value="<?php echo"$user_id"; ?>" class="sbutton">
which works in a nutshell, how ever, it's not user friendly and I can't access the user_id, when I use the $_POST feature, it saves the 'name' field.
I know this is long winded, I hope i've given you enough information, many thanks in advance.
It seems like there is another hidden field in there with the job ID, and each row has it's own <form> tags - so if you'll remove the check for the check field than you're fine.
Like that:
<?php
if($_POST['accept'])
{
$form_id=$_POST['fid'];
$customer=$_POST['customer'];
mysql_query("UPDATE job SET customer='".$customer."' WHERE f_id=".$form_id);
echo "<div class='form_ok'>Job has been updated.</div>";
}
?>
By the way - it's best that you'll check and secure the values from the $_POST with check for numbers and securing against SQL Injection with mysql_real_escape_string function

Using POST method to hide URL parameters

I understand that I am able to use the POST method for URL parameters to display data according to a specific variable, I know how to make use of the GET method - but I am told that the POST method can be used to hide the part of the URL that is like this.
/data.php?parameter=1234
What is the actual difference of the two methods in terms of URL parameters?
Below is some code that fetches data from a database according to the id of a specific link
<?php
//This includes the variables, adjusted within the 'config.php file' and the functions from the 'functions.php' - the config variables are adjusted prior to anything else.
require('configs/config.php');
require('configs/functions.php');
//This is the actual interaction with the database, according to the id.
$query = mysql_query("SELECT * FROM table WHERE id=" .$_GET['id'] . ";") or die("An error has occurred");
//This re-directs to an error page the user preventing them from viewing the page if there are no rows with data equal to the query.
if( mysql_num_rows($query) < 1 )
{
header('Location: 404.php');
exit;
}
//Here each cell in the database is fetched and assigned a variable.
while($row = mysql_fetch_array($query))
{
$id = $row['id'];
$title = $row['title'];
$month = $row['month'];
$day = $row['day'];
$photo = $row['photo'];
$text = $row['text'];
}
?>
On a separate page I generate links to the data.php file according to the ID like so:
<?php echo $content['title']; ?>
Forgetting that there are potential SQL injections that can occur through the above code, how would I go about making use of the POST method in order to hide the URL parameters, or at least not display them like this:
http://example.com/data.php?id=1
In order to use POST, you will need to use a <form> tag, and depending on how you are pulling up these URLs, it could be easier to use javascript to help out. Here's a basic example:
<form method="post" action="data.php">
<input type="hidden" name="parameter" value="1234" />
<input type="submit" value="Go" />
</form>
The Go button would POST the form data, and now in data.php you will be able to retrieve the value from $_POST['parameter']. Note that when using POST, you will probably want to redirect (HTTP 302) back to a page so that when a user hits the back button, the browser doesn't prompt to resubmit the form.
Using javascript, you could set the parameter input to a different value before posting the form.
Use method "POST" for your form. I had the same issue, just adding POST to the form removed the parameters from the URL
<form id="abc" name="abc" action="someaction.php" method="post">
<input type="text" id="username" name="username"/>
<input type="password" id="password" name="password"/>
<input type="submit" id="submit" name="submit" value="submit"/>
</form>
To POST values, a browser would have to use a form with method="post", or javascript simulating a form. Various developer tools (fireug, etc) can convert GET forms to POST forms, but generally, a form is what is required.
In theory GET requests should not have any side effects, and "should" be consistent from request to request. That is, the server should return the same content. In todays world of just about everything being dynamic, this might be of little practical design significance.
Whether you use GET or POST, the parameters will appear in $_REQUEST. The critical difference is that using POST allows the variables NOT to appear in URL history. This decreases the visibility of data such as passwords which you do not want to show up in URL history. To use POST instead of GET, simply produce <form method="POST" ...> in the document.
Even better is to store sensitive values (like user ids) in cookies, so that they don't appear in $_REQUEST at all. Since the contents of cookies are provided in extra HTTP request headers, not in the content, they are generally not stored as part of the history.
In order to use POST instead of GET, you would need to use an HTML form tag in your html, like so:
<form method="POST" action="/data.php">
<input type="hidden" name="parameter" value="1234" />
<button type="submit">Submit</button>
</form>
When submitted, your URL will just be /data.php and parameter=1234 will be in your (hidden) post buffer.
Make sense?
To do a POST, you have to use a form, or some javascript/ajax trickery. An <a> will only ever cause a GET request.
Note that POST requests can still have query parameters in the URL. It's not "normal" to have them, but they are allowed. The main difference being that with a GET request (ignoring cookies), the URL is the ONLY way to send parameters/data to the server. With POST, you can use both the URL, and the body of the POST request, which is where POSTed form data is normally placed.

SQL Comment table insert statement

I want to develop a system where a user should be able to post the comments on the author published news.
I am very much confused about the Insert Statement that i should be using to store the user commenting system, i have two mysql table one is news and another is comments below is the screenshot of two tables.
news
comments
in the comments table i have defined a foreign key (new_id) , in which i want to store the value that is related to the particular news for example a news with id no. 7, how do i achieve this dynamic feat? how do i automatically relate it to the news when a user post the comment (nevertheless to say that the user will be giving the input from the form )?
EDIT : I want to use One news article on one page.
thank you
Well first off you need to know how you are going to view a news item? Is this going to have all news articles on one page and below each news article is a to post new comments? If so then each of these forms generated per news article should have the news ID in the form potentially as .
Example:
<p>News article 1.</p>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<input type="hidden" name="new_id" value="1"/>
<textarea name="comments"></textarea>
<input type="submit" name="submit" value="Post COmment"/>
</form>
<p>news article 2</p>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<input type="hidden" name="new_id" value="2"/>
<textarea name="comments"></textarea>
<input type="submit" name="submit" value="Post COmment"/>
</form>
Then on this page at the top you can check for whether or not user pressed submit button:
<?php
if(isset($_POST['submit'])){
//$_POST['new_id'] is news article id
//$_POST['comments'] is comments for this
//sql to store new_id = $_POST['new_id'] and comments = $_POST['comments']
{
Alternatively:
Lets say on your home page you have links to each news article and you retrieve them on subsequent page using $_GET. So index.php displays news and getNews.php is where news is displayed. You could want to on index.php generate a link to getNews.php?id=
THis way on getNews.php you know which news article to get using $_GET['id'] and you can easily post comments to this using a similar technique to above, take $_GET['id'] and toss it into your form on getNews.php as hidden field.
Caution: be careful and sanitize your $_GET variable before using it.
?>
first your structure looks good.
i assume "new_id" is id of the newspost!
i would switch from datetime to timestamp. its range is smaller but i dont think you are gonna have posts in the past? and it has additional features like automatical timezone conversion.
anyways! the usual approach is to include the "news_id" as a hidden form field in the form that is used to submit the comment!
then you can fetch it with $_POST["whatever-you-named-it"];
and then you construct your insert statement... dont' forget to mysql_real_escape_string() every user supplied data to avoid mysql injection.
Generally that id (the id of the entity you're attaching something to) is either in the URI the form is POSTed to, or is simply a hidden element in the form.
For example:
<?php
//somehow you need to set this value, if the comment form is on the same
//page as the news then you should already have this id. If not, then you
//have to provide the 'stand-alone' comment page with the id you expect it
//to be using
$new_id = 7
<form method='post' action='/news/<?php echo $new_id ?>/comment/'>
<input type='hidden' name='new_id' value='<?php echo $new_id ?>'>
<input tyle='text' name='Name'>
...
</form>
With that form you can either parse the URI to determine what the foreign key should be, or use the hidden field.
Update: Showing how to use both $_GET and $_POST (so you don't have to parse the URI):
<form method='post' action='/comments/?new_id=<?php echo $new_id ?>'>
As always, check all user input, regardless of where it comes from (the URI, a POST a GET).
you could add an hidden input field to your comments form like this:
<input type="hidden" name="new_id" value="7"/>
Then in your php code you get the value via $_POST['new_id'] or $_GET['new_id'] depending on what method you're using.
The you can use the following code to generate the SQL:
$new_id = mysql_real_escape_string($_POST['new_id']);
$comment = mysql_real_escape_string($_POST['comment']);
$sql = "INSERT INTO comments (comment,new_id) VALUES ('$comment','$new_id')"
If shortened it, you still have to add the other values. But I hope now it's clear how you can do this.
If you don't want to use the hidden field you can add a get parameter to the action url like this:
<form action="your_script.php?new_id=<?= $new_id ?>">
Then you get it as $_GET['new_id'].
Update:
If you're concerned for security and want to make sure nobody ist trying to forge a request, you should take a look at http://www.codewalkers.com/c/a/Miscellaneous/Stopping-CSRF-Attacks-in-Your-PHP-Applications/1/
You asked about the SQL INSERT statement, so I assume you are concerned simply with the SQL...
Using AUTO_INCREMENT, LAST_INSERT_ID(), and TRANSACTION...
Set [news].[id] to be an AUTO_INCREMENT value type. Then using a transaction, you should be able to do something like this:
START TRANSACTION;
INSERT INTO news VALUES('2010-08-21','','','','','')
INSERT INTO comments VALUES(,'2010-08-21','','','','','',1,LAST_INSERT_ID())
COMMIT;

Categories