0

I created my own forum system, and one feature of that system is that users can link images in their posts. To be clear, they can surround their image link with BBCode like this:

[img]https://www.example.com/someimg.jpg[/img]

I then use regex to format the output of their post that is sent from the database, turning it into HTML:

<img src="https://www.example.com/someimg.jpg" alt="user-img" />

I thought this was fine until I had to create a system to allow users to upload their own profile pictures, during which time I researched and implemented several security checks to help prevent malicious data from being sent via image uploads (check file types, change the image's submitted name before storing, don't allow direct access to these images, etc.). I also read this question which mentions some potential security issues regarding user-generated HTML, but is more about letting users directly edit HTML.

I know numerous websites, including Stack Overflow, that allow users to insert images into their posts/comments. What's stopping someone from uploading a tampered image to their own site and linking it on another site? What can I do to make my current method safer?

Ginger and Lavender
  • 436
  • 1
  • 8
  • 21
  • 1
    You can't worry about tampered images on other sites. How would you detect if a benign image is replaced by a malicious one? Leave that problem to the image hoster and the browser developers (if you don't host the image). Your main worry should be about html injection aka cross site scripting. If you have other BBCodes, and allow nesting them, there could be injection vectors that produce horrible corrupt html/js code that is still executed by all moder browsers. But that really depends on your BBCode implementation. – jh1711 Sep 23 '18 at 21:59
  • Thank you for clarifying this for me. I didn't mention it in my question, but I have taken many steps to prevent XSS with my BBCode parsing (and of course using `htmlspecialchars` for output); I was just wondering if I needed to do something extra with images. – Ginger and Lavender Sep 23 '18 at 22:03
  • some sites proxy them (external images) to remove user header information. you could even proxy them and scan them to check they are actully images, to much woprk in my opinion. `[img]https://www.example.com/someimg.jpg[/img]` -> `user-img` –  Sep 23 '18 at 22:15
  • @Dalsia, I didn't mean to imply that you are sloppy with XSS. But sometimes there are unusual attacks, because your BBCodes add the filtered characters. I don't think you need to worry about images, apart from the obvious problem, that the image could be replaced by something you don't want. – jh1711 Sep 23 '18 at 22:26

1 Answers1

2

As IdontDownVote mentioned you could proxy the image request through your server and check it for a valid image type.

This has some good points:

  • Malicious images won't get displayed.
  • Your users' privacy is protected as the request to the third-party is issued by your server.

One example solution for the proxy-script that checks for valid images of the types PNG, JPEG, BMP and GIF could look like this:

//IMPORTANT: Implement some sort of check that no local files get echoed by accident!

$img = filter_var($_GET["src"], FILTER_SANITIZE_URL); //Only handle true urls
$type = getimagesize($img)[2] ?: false; //Get src type, "wrong" images would have false

switch($type){ //Set correct content-type and output image
    case IMAGETYPE_GIF:
        header("Content-Type: image/gif");
        echo file_get_contents($img);
        break;
    case IMAGETYPE_BMP:
        header("Content-Type: image/bmp");
        echo file_get_contents($img);
        break;
    case IMAGETYPE_JPEG:
        header("Content-Type: image/jpeg");
        echo file_get_contents($img);
        break;
    case IMAGETYPE_PNG:
        header("Content-Type: image/png");
        echo file_get_contents($img);
        break;
    default: //Create fallback image
        $im = imagecreatetruecolor(100, 100); //Create new 100x100 image
        $bg = imagecolorallocate($im, 255, 255, 255); //Set white background
        $textcolor = imagecolorallocate($im, 0, 0, 255); //Set text-color to blue
        imagestring($im, 5, 0, 42, "Invalid IMG", $textcolor); //Draw text to image
        header("Content-Type: image/png");
        imagepng($im); //Output image
}