0

I have written some jQuery + PHP code that takes the HTML from an element on a webpage and saves it on server. Here is the code that I am using:

var page = {
    'html': document.querySelector("article").innerHTML,
    'url': 'path/current/webpage.php' or (<?php echo "'$current_page'"; ?>) 
    // Both give same 'url' value. This is not an issue. 
};

$.ajax({
    url:'https://example.com/update.php',
    type:'post',
    data: page,
    success:function(data){
        window.location.reload();
    }
});

Here is my code for update.php:

$content = $_REQUEST['html'];
$page = $_REQUEST['url'];
file_put_contents($page, $content, LOCK_EX);

I am not very comfortable with dataType and contentType so I skipped them initially. However the request succeeded sometimes but gave 403() error other times.I did a little research and found that this might be due to lack of dataType and contentType. So, I used the following values:

contentType: 'text/plain; charset=utf-8',
dataType: 'html'

I no longer get any errors but the pages are not actually updating. I also tried setting the values to:

contentType:'application/json',
dataType: 'html'

This time too, I did not get any 403() errors but the page would not actually update.

Does the post data needs to be accessed differently based on the value of contentType like 'application/json' or 'text/plain; charset=utf-8'? Because the updates don't seem to show up on the webpage even with a 200 response code.

Using application/x-www-form-urlencoded; charset=UTF-8 updates some pages but gives 403() error for others.

Vineet Sharma
  • 221
  • 2
  • 11
  • I don't think `'url': ` is possible in JS – Deepansh Sachdeva Sep 09 '17 at 17:10
  • 1
    @DeepanshSachdeva I am using `script` tags inside a `.php` file. – Vineet Sharma Sep 09 '17 at 17:10
  • 1
    `contentType` is the type of the data you're sending. `dataType` is the type of data you're receiving. You don't receive any data back from the request, so the latter is irrelevant. `contentType` is by default `application/x-www-form-urlencoded; charset=UTF-8`, which should be fine for your usage. An intermittent 403 error is most likely from a configuration problem on the server and is not related to the data you're sending in any way – Rory McCrossan Sep 09 '17 at 17:13
  • It is visible to me as well but I think that'll not work and is breaking the code in your case. Also that's an unacceptable coding practice to do so. – Deepansh Sachdeva Sep 09 '17 at 17:14
  • @DeepanshSachdeva no it's not, its fine. What are you talking about? – Rory McCrossan Sep 09 '17 at 17:14
  • @DeepanshSachdeva: We have no reason to think that there's any problem with that part of the code. Whether it's good style is off-topic here. – T.J. Crowder Sep 09 '17 at 17:14
  • @RoryMcCrossan But `application/x-www-form-urlencoded; charset=UTF-8` updates some pages and gives 403 on others. However, `'text/plain; charset=utf-8'` works everywhere but does not actually update the pages. Shoud the content inside `update.php` change based on content type? – Vineet Sharma Sep 09 '17 at 17:15
  • 1
    That depends entirely on what you're doing with the data. In either case this would seem to be more of a PHP issue that a JS one. – Rory McCrossan Sep 09 '17 at 17:15
  • @RoryMcCrossan that line I was pointing has been hardcoded in the edit. See my first comment, when he is using php echo to add url there. Is it ok? – Deepansh Sachdeva Sep 09 '17 at 17:17
  • 1
    The OP replied `I am using script tags inside a .php file.`, so even before the edit their logic was correct. – Rory McCrossan Sep 09 '17 at 17:17
  • Oh! That's fine then @RoryMcCrossan – Deepansh Sachdeva Sep 09 '17 at 17:20
  • @RoryMcCrossan Is the way I access the AJAX data inside `update.php` need to be different for different `contentType` values? – Vineet Sharma Sep 09 '17 at 17:24
  • 1
    @VineetSharma: Yes, it would; that's the point of telling the server what kind of data you're sending it. If you say you're not sending form data, it won't parse it into the individual fields that you access via `$_REQUEST` (or `$_GET`/`$_POST`/etc.). The default is what you want for the way you're getting those fields. – T.J. Crowder Sep 09 '17 at 17:30
  • Thanks @T.J.Crowder but `application/x-www-form-urlencoded; charset=UTF-8` keeps giving me 403() errors. Do you mean to say that if I set `contentType` to `application/json` I can't access the AJAX data using `$_REQUEST['html']`? – Vineet Sharma Sep 09 '17 at 17:35
  • 2
    @VineetSharma: Yes, that's what I'm saying; if you posted JSON (which would mean changing more than just the `contentType`), you'd have to [read the body](https://stackoverflow.com/questions/8945879/how-to-get-body-of-a-post-in-php#8945912) and parse it. As Rory said, 403 errors are unlikely to relate to the `contentType`. You should look for other reasons the server would refuse to satisfy the request. For instance, as you're posting HTML, perhaps you (or your web host) has some kind of anti-script-injection protection going on. You'll have to track that down. – T.J. Crowder Sep 09 '17 at 17:37
  • @T.J.Crowder I have actually spent more than two days trying to figure out why I keep getting 403() errors "randomly" but I can't find something definitive. It is bumming me out so I decided to try some other `contentType`. – Vineet Sharma Sep 09 '17 at 17:44

1 Answers1

1

As Rory said (as did I, in an answer I wrote then deleted when I saw his comment; he was right to comment instead), a 403 response code probably doesn't mean there's a problem with either dataType or contentType. You should look for other reasons the server would refuse to satisfy the request. For instance, as you're posting HTML, perhaps you (or your web host) has some kind of anti-script-injection protection going on. You'll have to track that down, perhaps with your hosting company.

But two things: Some info for completeness, and a potential workaround:

dataType is the type you expect back from the server. contentType is the type of data you're sending to the server.

For the request you're sending, leaving off contentType is correct, because the default jQuery will use is what PHP will expect to see.

You shouldn't have to specify dataType at all; instead, you should ensure the response carries the correct Content-Type header. That means ensuring that your server is configured correctly (for static content) and that your PHP code sets the correct header if necessary via header("Content-Type: data/type-here") The only reason for specifying dataType is if you don't control the server and you know it sends back the wrong type.

If you need to try to work around it, first ask: What if someone sends me malicious HTML directly, not through my web page? The answer is: You need to be careful with what you do with the HTML. For example: If you are going to store this HTML and then display it (as HTML) to a user, that's a Cross-Site Scripting vulnerability and you have to rigorously sanitize that HTML before doing that.

Do not proceed with any workaround until you've answered that question for yourself.

Okay, so in terms of working around it (once you have robust safeguards in place): You might send JSON rather than a standard form, in hopes that whatever is rejecting the forms won't look at it. To do that, you'd change your ajax call:

var page = {
    html: document.querySelector("article").innerHTML,
    url: <?php echo "'$current_page'"; ?>
};
$.ajax({
    url:'https://example.com/update.php',
    type:'post',
    data: JSON.stringify(page),
    contentType: 'application/json; charset=UTF8',
    success:function(data){
        window.location.reload();
    }
});

Then on the PHP side, you'd read that JSON and parse it (reading code below taken from this answer):

$entityBody = json_decode(stream_get_contents(STDIN));
$content = $entityBody['html'];
$page = $entityBody['url'];
file_put_contents($page, $content, LOCK_EX);

Again: Please do not use this unless you have robust anti-XSS safeguards in place. And again, if you do haev robust anti-XSS safeguards in place, you might be able to just use a normal form by changing your server config.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • What if someone sends me malicious HTML directly, not through my web page? I am answering this question here. Let me know if what I am doing is still insecure. :) The clickable button and AJAX script only exist after I have successfully set a cookie in my browser. I set this cookie only after authenticating myself. :) Is Cross-Site Scripting still an issue because only I know the usernames and password to authenticate the cookie setting. – Vineet Sharma Sep 09 '17 at 18:06
  • 1
    @VineetSharma: Nope, not safe. :-) Even if you're the only user, cookies are trivial to steal with a man-in-the-middle attack. And if you're not the only user: Hi, I'm a malicious user. I authenticate, then grab the cookie value and send you malicious HTML. You're pwned. ;-) I suggest researching anti-XSS and similar and if you have a question about whether what you come up with is secure, etc., post it with the relevant tags. (I'd have to brush up before accepting HTML from a web page I didn't rigorously sanitize.) – T.J. Crowder Sep 09 '17 at 18:11