-
Posts
4,207 -
Joined
-
Last visited
-
Days Won
209
Everything posted by Jacques1
-
You should do both: Make an educated guess and then allow the user to override the setting. The desired language is usually specified in the Accept-Language request header. In PHP, you can get the value with $_SERVER['HTTP_ACCEPT_LANGUAGE']. The timezone can be chosen based on the IP location. Or you can use client-side scripting (again it makes sense to do both in case JavaScript is turned off).
-
This array feature which you appearently know from PHP is actually very exotic and really only makes sense in the super-sloppy PHP philosophy. Technically speaking, you simply cannot apply the index operator to the empty value t['key1']. There's no such thing as null['key2']. If you try this in Ruby, your script will blow up with an error message. The same is true for Python. The only reason why PHP doesn't blow up is because it's specifically designed to accept errors. Instead of telling you to fix your code, it will guess what you mean and create a new subarray for you. So this isn't how languages normally works. It's a PHPism.
-
The Location header actually isn't as safe as one might think. For example, all PHP versions up until 5.1 were vulnerable to Response Splitting Attacks where the attacker could inject a CR LF sequence after the URL and then either add new headers (e. g. to overwrite critical cookies) or manipulate the response body. Also note that neither PHP_SELF nor REQUEST_URI are necessarily valid. Webservers are extremely fault-tolerant, which means they accept anything as long as they can make sense of it. For example, I could easily inject raw control characters into the REQUEST_URI. This absolutely shouldn't happen as it violates even the most basic syntax rules for URLs, but it's still possible. So I'd take a much more conservative approach. Instead of relying on the webserver and PHP to give you a safe URL, you should assemble the URL. That is, pick the target path, make a whitelist of permitted query parameters and use http_build_query() to make sure the URL is actually valid: <?php const TARGET_PATH = '/path/to/target'; $permitted_target_parameters = [ 'foo' => null, 'bar' => null, ]; $filtered_target_parameters = []; foreach ($_GET as $parameter => $value) { if (array_key_exists($parameter, $permitted_target_parameters)) { $filtered_target_parameters[$parameter] = $value; } } $target_url = TARGET_PATH.'?'.http_build_query($filtered_target_parameters); header('Location: '.$target_url); exit;
-
remove malicious php from image uploads with IMagick
Jacques1 replied to bonecone's topic in PHP Coding Help
Yes. Again: A PHP script which serves image data with the right content type behaves exactly like a physical image in every aspect. It's the exact same thing. In the HTTP context, an “image” is really just a URL pointing to image data. Where this data comes from is irrelevant. It might be an actual file served by the webserver, it might be a PHP script reading files from outside of the document root, it might be dynamically generated with no files involved. The client neither knows nor cares. As requinix already told you, there is no difference. There cannot be a difference. In both cases, the browser makes a request to the server (unless the image is already in the cache), fetches the image data and displays it. There is no magical “View Image” request in the HTTP protocol. It is possible to suggest to the client that a file should be downloaded, but that's an entirely different feature which none of us has suggested. If you don't believe us, try it yourself. -
remove malicious php from image uploads with IMagick
Jacques1 replied to bonecone's topic in PHP Coding Help
As long as the PHP script serves the image data with the right content type like image/png, it behaves exactly like a physical image. From the client's perspective, there's no difference. You could even use the same URLs by rewriting https://uploads.yoursite.com/images/<ID> to https://uploads.yoursite.com/image.php?id=<ID>. -
remove malicious php from image uploads with IMagick
Jacques1 replied to bonecone's topic in PHP Coding Help
Trying to remove “malicious” content from a file is naive, because there are potentially infinite ways of how a file might become harmful in a certain context. The example attack above uses EXIF tags which can easily be removed, but what if the image data itself gets misinterpreted as code? Removing this data would damage the image (regardless of whether the user actually has bad intentions), and even then you cannot be sure that you haven't missed anything. A much more effective method is to not put the files into any executable context: The uploaded files should not be placed in the document root and not be accessible directly. Instead, you'd write a PHP script which reveives the filename (or some identifier), reads the corresponding image from an isolated folder outside of the document root and send the data to the client. To the client, this is just like a plain image file. But for you, it's much more secure, because the files won't ever be executed by the PHP interpreter. Choose a random filename and pick the extension from a predefined whitelist of permitted image extensions (or omit the extension altogether). The filename provided by the client should be treated as metadata and not actually used. Make sure the webserver only executes specific scripts from specific folders (as opposed to the usual “everything that ends with .php” policy). Also make sure to keep permissions at a minimum to limit the possible damage. Note that files may also contain client-side code, so you need to protect your users as well: Serve the files from a separate domain like uploads.yoursite.com. This will prevent many attacks due to the same-origin policy. Use modern security mechanisms like Content Security Policy to prevent execution of code. -
The code is vulnerable to pretty much every attack known to man. And since you had the ingenious idea of putting this stuff on a public webserver, your machine is now open to anybody who can type “sqlmap” on their keyboard. I wouldn't be surprised if your code is being exploited right now. Since you seem to think that requinix' warning was just a joke, I'll put this more bluntly: Stop it right now. This is much more serious than your little toy website throwing errors. You're putting everybody at risk, and if you keep doing that, you will get into trouble. So shut down your server, do a factory reset and don't even think about uploading your code until you actually know what you're doing. It's great that you want to learn PHP, but you do not ever use a public server as your personal playground. Install XAMPP on your PC.
-
A PDO statement doesn't have a bind_param() method. That's code for the MySQLi extension which is an entirely different database interface not related to PDO in any way. It looks like you've randomly copied and pasted code from different sources. This doesn't work. You need to pick one interface (PDO is generally preferable) and then learn how to use it. The PHP manual is a good place to start. There's also a well-written tutorial on hashphp.org.
-
PHP does have a command-line interface, and your script works just fine when executed from the console. What exactly happens on your PC? Are you saying you see all output but cannot input anything?
-
The range() function cannot do this (unless you were to convert the strings into numbers, which is cumbersome). But you can use a for loop: for ($str = '1A'; $str <= '5D'; $str++) { var_dump($str); }
-
The effective form action is determined by the browser, and the browser doesn't know anything about PHP or how you've organized your scripts on your server. If there's no explicit action, the form data is sent to the document's address which may or may not point to the script which was original called.
-
Is it really so hard to google for the MySQL manual? Date and time literals You specifically asked for a date type, and that's what DATE is for. Using a timestamp when there's no time doesn't make sense.
-
No, no, no. Stuffing a sequence of values into dozens of separate variables like $data_2010, $data_2011, $data_2012, $data_2013, ... is yet another bad idea and will turn the already shaky codebase into a nightmare. Even a trivial task like iterating over the years now requires dynamic variable gymnastics, because the only data structure which actually knows all values is the internal PHP symbol table. Good luck using that for more complex tasks. This is not helpful. Right now, the OP has one problem. With the function above, he has two problems and will be back in a week asking us to write a workaround for the workaround.
-
Query help - looking for members of two different groups
Jacques1 replied to simonp's topic in MySQL Help
I repeat: SELECT users.uid FROM users JOIN users_roles ON users.uid = users_roles.uid WHERE users_roles.rid IN (7, -- make sure that the user is in *both* group 7 and 8 by -- counting the number of groups: GROUP BY users.uid HAVING COUNT(*) = 2 ; No, the point is to count the rows. -
Query help - looking for members of two different groups
Jacques1 replied to simonp's topic in MySQL Help
I think the OP wants all users who belong to both the group 7 and the group 8: SELECT users.uid FROM users JOIN users_roles ON users.uid = users_roles.uid WHERE users_roles.rid IN (7, GROUP BY users.uid HAVING COUNT(*) = 2 ; -
Deleting ID's associated with a parent ID
Jacques1 replied to CloudBreaker's topic in PHP Coding Help
What exactly is the problem here? Why do you need the project ID in addition to the file ID? Besides that, your code has fundamental problems, so I recommend you start with the basics before you jump to more advanced stuff: Learn how to safely pass values to queries using prepared statements. Right now, anybody can inject malicious SQL commands through the URL parameters. Make sure you understand the purpose of GET and POST requests. A GET request is only for retrieving data (hence the name), it must not change data. Right now, anybody could make you delete arbitrary files simply by using an image with a URL like https://yoursite.com/submittal-view.php?delete=123. As your browser makes a request to the URL to retrieve the image data, your server deletes the image. To prevent this, you need to use a POST request together with an anti-CSRF token. Do not insert raw values into the HTML markup as this allows anybody to inject malicious JavaScript code. You need to HTML-escape the strings first. -
There's a fundamental difference between localhost and a public domain name, so that wasn't really a good example Actually, I'm not even sure what you're saying now. That you have trouble with all sites and clients which suppress the referrer? Well, there's not much you can do about this. Really the only difference between an “internal” request from your site and an “external” request from a hotlinking site is the referrer. If hotlinking is actually a serious problem for you (not just a vague fear), your only chance would be to not have publicly accessible images at all, to the disadvantage of usability and possibly performance: Consider restricting the images to registered users. It's also possible to embed the images directly into the page without ever making them available via a URL. Note that this will increase the effective image size by 1/3 (due to the encoding) and might have a negative impact on the (perceived) performance. You could embed a nonce into the image URLs so that the image can only be loaded once right after the original HTML page. This again might come with a lot of problems, so I'd be careful with that. But again: Is hotlinking really a problem? Have you actually analized the traffic caused by hotlinking?
-
Using bindParam() or bindValue() together with an explicit type is definitely the more correct variant. While it's usually fine to just use strings for all parameters (that's indeed the default type), there are some nasty edge cases. To be honest, the only reason why I use the array variant is because it's a lot shorter. As a compromise, one could keep using arrays but add explicit type casts to the query itself.
-
Question about deleting where no matching record to join
Jacques1 replied to sKunKbad's topic in MySQL Help
The second query is syntactically invalid. See the manual for how to write a multi-table DELETE query. -
What makes you think your admin panel is more secure now? The IP whitelist you've proposed is extremely poor (as it's based on the naive assumption that one IP address equals one person), and the implementation is even worse. Of course you might say that it's still better than nothing, but that's not the case. This .htaccess hack only gives you a false sense of security and distracts you from the real solutions. You want to protect the admin panel? Force the admins to use purely random passwords which are stored in a password manager like KeePass. If the passwords are sufficiently long (e. g. 32 hexadecimal characters), they're effectively immune to many attacks. Make sure you use a strong password hash algorithm like bcrypt. For even more security, consider using public-key authentication via TLS instead of password-based authentication. This requires some technical knowledge, though. Double-check your code for common security vulnerabilities (especially cross-site scripting, SQL injections and cross-site request forgery). Unlike your homegrown IP stuff, those features actually work and have proven themselves in practice many times.
-
And how does your server-side script determine valid requests? I mean, besides checking the referrer.
-
I'd definitely prefer the shorter ID with 26 digits.
-
This is still complete nonsense, but appearently you don't care.
-
None of this makes any sense. The only way a user could access your images directly via localhost if they're actually on the server. So whom are you trying to protect against? Yourself? Your own server admins? Besides that, there's simply no way to forcefully prevent other sites or people from accessing a public resource. The best you can do is ask people not to hotlink, and that's what your current referrer check already does. As soon a site or an individual client suppresses the refferrer, you're out of luck.
-
Every byte sequence can be interpreted as a number (e. g. as the binary representation of an integer). However, the class uses PHP integers, and that means the input is limited to just a few bytes. A more reasonable approach is to encode the input bitwise, which is what the second class does. This way there are no specific limits. I assume you're talking about 128-bit strings. In Base32, every digit carries 5 bits. So you need ceil(128/5) = 26 digits to represent 128 bits.