phppup Posted April 9, 2021 Share Posted April 9, 2021 (edited) I thought that after a fully sanitizing scrub of uploaded images, a simple display gallery would suffice. Then I was advised to change image names and rename directories for added security. Yet after all these precautions, it seems it's still insecure to exhibit user images? I recall a suggestion to have images SERVED (rather than using HTML <img> tag), but cannot find a method, starting point, or clear rationale for this. Guidance, advice, and insight to point me in the right direction, please. Edited April 9, 2021 by phppup Typos Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/ Share on other sites More sharing options...
requinix Posted April 9, 2021 Share Posted April 9, 2021 What? Scrubbing what? Change what for security? What's insecure, and what are you saying about "served" somehow not using <img> tags? Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585686 Share on other sites More sharing options...
phppup Posted April 9, 2021 Author Share Posted April 9, 2021 I want to allow users to upload images and then create a gallery. I am already checking file extension and taking other measures to ensure that the file is in fact a real image. I am changing the image name, so that even if the file is malicious, it is not easily accessible. But I'm not sure of the best way to display the images afterward. If images are uploaded to the XYZ directory, is it wise to display them from that location? Is it insecure for an image to be viewed from /blah/blah/blah/XYZ/renamedimg.jpg ? What is the safest way to approach this? Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585687 Share on other sites More sharing options...
requinix Posted April 9, 2021 Share Posted April 9, 2021 1 hour ago, phppup said: I am changing the image name, so that even if the file is malicious, it is not easily accessible. But you want people to see the image. It's supposed to be easily accessible. That said, people should not be able to dictate filenames on your server, so generating your own name for them is still a good thing.  Quote But I'm not sure of the best way to display the images afterward. If images are uploaded to the XYZ directory, is it wise to display them from that location? Is it insecure for an image to be viewed from /blah/blah/blah/XYZ/renamedimg.jpg ? What is the safest way to approach this? It doesn't really matter where the images are. Consider the avatars on this forum: mine is /uploads/monthly_2021_02/catra.thumb.png.4c523d979ea05f55c35f4277018effe8.png. The only thing that shows is the upload date (nobody cares) and original filename (arguably useful information). It's fine. Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585690 Share on other sites More sharing options...
phppup Posted April 9, 2021 Author Share Posted April 9, 2021 Am I looking for solutions when no problem exists? IÂ really thought I read something about a security risk in letting the directory that was home to images become visible. There was certainly a cautionary note to NOT let users name directories. I assumed that this (like the name of a file) was to prevent access (if a malicious file were uploaded). If none of this matters, why not allow a user to name a folder and retain image names? After all, access to the images will be readily available anyway, right? Am I not making an obvious connection here? Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585691 Share on other sites More sharing options...
requinix Posted April 9, 2021 Share Posted April 9, 2021 4 minutes ago, phppup said: Am I looking for solutions when no problem exists? Mostly. Let people upload images to a public location as long as access is supposed to be unrestricted and you do a good job verifying that the files are indeed images. If you wanted to allow all sorts of file types then this conversation would be going a different way and you'd need to consider making them private after all. Some people will say you should do it anyways. Me, not so much, because it's easy to verify that a file is an image and to ensure that it is only ever considered to be an image. The alternative is to not do that - to make them private and accessible through a script. And there are non-security benefits to that, like making it easier to count views, and full customization of the URL (with rewriting). You might as well consider whether you want to do that, but if you don't now and change your mind then you can use URL rewriting in the future to make it happen pretty easily. As for the user creating folders and specifying exact file names? No. You need to retain 100% control over exactly what each file is named and where it is placed on your server. You can incorporate the original name into the name you use, if you want, and for an image hosting thing that would probably be a good idea, but ultimately your code decides what to do. But you know, if you want to stop thinking about this, just go with the private thing. It's not wrong to do it. You have to worry about MIME types and file caching and partial responses, but those are solved problems. Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585692 Share on other sites More sharing options...
phppup Posted April 9, 2021 Author Share Posted April 9, 2021 (edited) At this point I think I'd better just stick with the areas that have problems I can overcome. Perhaps later I'll research the "private" aspect. I guess my initial thinking wasn't totally off-base. If I've VALIDATED the file fully, and changed the name anyway, then any malicious efforts should be nullified. So even if a bad intent were initiated, it should be defused. But why not let a user name a directory? Clearly locating the folder contents is not the issue? Placement? If I have a designated destination and RegEx naming requirements implemented, is there still a risk that I'm not seeing? Edited April 9, 2021 by phppup Typos Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585696 Share on other sites More sharing options...
requinix Posted April 10, 2021 Share Posted April 10, 2021 22 hours ago, phppup said: If I've VALIDATED the file fully, Validated it fully as far as you know. Quote and changed the name anyway, then any malicious efforts should be nullified. So even if a bad intent were initiated, it should be defused. Unless you consider malicious effects on the client, but dealing with those is a hassle. Quote But why not let a user name a directory? Clearly locating the folder contents is not the issue? Because the user should not have control over how things are named on your server, and because directories are irrelevant. If you want to make it look like there are directories then do that on the frontend - the actual URLs don't matter. Quote Placement? If I have a designated destination and RegEx naming requirements implemented, is there still a risk that I'm not seeing? Maybe. Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585713 Share on other sites More sharing options...
phppup Posted April 11, 2021 Author Share Posted April 11, 2021 16 hours ago, requinix said: Maybe. What is it that I (might not) be seeing? What potential problems am I inviting? Or is this just a macho induced control issue? If a sub-folder named userDirs is designated for users to create folders with names that they want, where is the harm? If a user creates folder "puppy" and instead I initiated the new folder 345 (but I equate 345 to puppy), they will still see a URL path /blah/blah/userDirs/345, right? So a hacker will not have been stalled, will they? If the folder is not allowed to contain any . $?<>/ shouldn't that protect me? Or perhaps limiting name size and allowing only alphanumerics is better? I still feel like I'm missing a valuable piece to the puzzle. Insight, please. Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585724 Share on other sites More sharing options...
requinix Posted April 12, 2021 Share Posted April 12, 2021 10 hours ago, phppup said: What is it that I (might not) be seeing? What potential problems am I inviting? My point is that it's only possible to validate and protect oneself against things that are known. Someday, someone will come up with a new attack and wasn't being protected against because it wasn't known about.  10 hours ago, phppup said: If a sub-folder named userDirs is designated for users to create folders with names that they want, where is the harm? Do you let strangers come into your home and use your toilet?  Before your next post where you shotgun another dozen questions at me, try to find the answers yourself. I only have so much time in the day. Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585746 Share on other sites More sharing options...
kicken Posted April 12, 2021 Share Posted April 12, 2021 11 hours ago, phppup said: If a sub-folder named userDirs is designated for users to create folders with names that they want, where is the harm? What if 5 different users want to make the folder "puppy"? Do you just mix all their files in that folder? What if their files are also all named "cutest.jpg"? Whoever uploads last gets the spot? That's one of the main reasons I just always generate a random name for the actual storage system of uploaded content. You don't have to deal with conflicting names. I generally just do something simple like: $ext = pathinfo($originalName, PATHINFO_EXTENSION); $newName = bin2hex(random_bytes(8)) . '.' . $ext; If I want to serve the files directly.  If I serve them via a script instead then I don't worry about the extension and just generate the random name. The original name and MIME type get stored in the db. If you want keep the original names / let users make directories then at minimum isolate each user into a folder you've defined that they cannot manipulate. For example, create a folder based on their auto-generated user ID from the database. Make sure you validate against path traversal attacks so they can't break out of that isolation.  Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585749 Share on other sites More sharing options...
MadTechie Posted April 12, 2021 Share Posted April 12, 2021 Let me start by saying phppup, your questions are very unclear, This makes it very difficult to help and will put people off offering help, You can save the images in a folder(s) or blobs in a database or save the image to a file and refer to it as via a script, Now, with "serving images" you will need to use the img tag when you display in html, you might use base64 instead of a path, e.g. URL vs BASE64 <!--URL image --> <img src='https://forums.phpfreaks.com/uploads/monthly_2020_10/logo-light.png.8ca2dc089c4e8fa3336b49fa0855692d.png' /> <!--Base64 image--> <img src="data:image/png;base64,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" />  If you are trying to restrict access then store the images outside public access and display via a script, <!--URL to image script --> <img src='image.php?hash=hsdgfhjsdghgsdjgj' /> //image.php $path = 'path to images outside public_html'; if($no_access){ exit(); } header('Content-type:image/png'); readfile($path.$_GET['hash'];  I hope this helps with some direction . Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585759 Share on other sites More sharing options...
phppup Posted April 14, 2021 Author Share Posted April 14, 2021 (edited) Quote What if 5 different users want to make the folder "puppy"? Do you just mix all their files in that folder? What if their files are also all named "cutest.jpg"? Whoever uploads last gets the spot? @kicken Thanks for the insight. I think/hope that I've got that figured out already, but I'll re-examine again.  Quote Make sure you validate against path traversal attacks so they can't break out of that isolation. I've been trying to cover that case too. Perhaps I'll need a new thread, but I found it quite revealing while working on "file sanitization" when I discovered that Lil Bobby Tables could access my data. I've run tests where I added ?file=../../etc/passwd To the end of a php URL, but gotten nothing unexpected. Am I just lucky? Already secure? Or a bad hacker? How can I trigger a negative result to help me implement a more positive security protocol? Edited April 14, 2021 by phppup Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585819 Share on other sites More sharing options...
gizmola Posted April 14, 2021 Share Posted April 14, 2021 There are a lot of different ways to run PHP. You can't separate a security strategy from the operating system, privilege of the web server, or privilege of the PHP script and the user it runs as. There are also bugs and gotchas that can occur, not to mention differences between operating system filesystems as to the characters allowed to be used in a filename. Requinix and Kicken both have a lot of real world experience, so they are going to provide you advice that is also opinionated. Personally there is very little benefit and a lot of potential risk to allowing users to create their own directories and files on your server, with names of their own choosing. You can always store this user input in a table, and utilize the name in various features if you really want to, but don't forget that a single bad actor could be crafting a name that may have no effect on your server, but could launch an exploit on the system of an end user.  Obvious concerns are when people try and craft paths that traverse your file system using slashes and periods.  Another concern is file names that could trick parsing like file.jpg.php or some other name that might trick your system into executing code.  A user could be using a character set that isn't supported by your file system, again causing a potential exploit that you aren't aware of. Or just allowing a name that causes your system to malfunction, because the name of the file includes case sensitivity or insensitivity, that either tricks or breaks your system entirely. Many OS's allow filenames that include spaces, tabs, and all sorts of other non-printable characters. Do you really want to open up your server, to the possibility of users creating hidden directories full of god knows what type of files, which perhaps appear to your system to be valid, but contain hidden payloads?  Quote Link to comment https://forums.phpfreaks.com/topic/312447-serving-images/#findComment-1585822 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.