I'm making a website with some image galleries.
I want to do as little backend as possible. I have the images separated into folders. I have a PHP script that fetches the contents of a directory specified by a get param. fetchFiles.php?dir=./art. Javascript sends a fetch there and it returns a JSON array of image file names and creates images with an src of. I would like to have it so that PHP can only access things in the directory the script it's executing in, so someone can't access all the directories on the server.
fetchFiles.php
<?php
echo json_encode(
array_values(
array_diff(
scandir($_GET['dir'], SCANDIR_SORT_ASCENDING),
array('.', '..', 'fetchFiles.php')
)
)
);
?>
First of all, don't ever allow the user the ability to control input that directly affects your code. This conflating of code and user-supplied-data is precisely what leads to insecure code.
Instead of letting the user decide what directory your PHP should look in, let PHP decide what directory it should look in.
Instead of:
scandir($_GET['dir'], SCANDIR_SORT_ASCENDING);
Do this:
const PICTURES_DIR = '/path/to/pictures/';
scandir(PICTURES_DIR, SCANDIR_SORT_ASCENDING);
If you must let the user supply some part of the input the least you can do is use a Whitelisting approach rather than just opening up your entire code to all sorts of vulnerabilities.
$whiteList = ['/path1/', '/path2/', ...];
if (in_array($_GET['path'], $whiteList)) { // It's OK
} else { // Ohnoes :(
}
Now, PHP has something called a open_basedir restriction which prevents PHP from being able to go above a certain base directory, but really if you find yourself doing this just to be so lazy as to allow arbitrary user input to control your code you're already setting yourself up for failure.
Security is built in layers. It's not a silver-bullet.
Related
I'm hooking into a separate page (same domain) and pulling it into the current page using $.load, which would be fine, if I was doing it for the whole page, but I'm not, I'm just doing it for the JavaScript code in that page. I was wondering if it's possible to load all the script tags from said page into the current page?
I'm currently using the below code:
var newMessageURL = $('#lnkCompose a').attr('href');
$('#hiddenScriptLoad').load(newMessageURL);
Is said page on the same domain or do you have access to it? You will run into trouble with the cross domain origin policy otherwise.
If you do have access, the only way is to parse the html using a regex statement or html parser and pull the scripts manually.
This sounds like a very hacky approach though and I'm not really sure why you'd want to do this.
If you have access, get the page contents and then use the below to get the script tag sources.
text.match( /<script src="scripts\/(.*?)\.scripts\.js"><\/script>/g )
Credit Javascript regex to get src url between script tag
var newMessageURL = $('#lnkCompose a').attr('href');
$('#hiddenScriptLoad').load(newMessageURL);
The above code will load all the contents you have in the second file and it will also import any javascript codes you have there. But the codes you'll have in second file will not work and wont get into action unless you call to them from first page using a function call or in any other manner.
If you just want to separate your js codings and html and have them in two separate files, it would be better to use PHP to import the second file into the first one and in this way, when the page is loaded in the client browser, it will render it as it was just a single file containing both contents. Ex..
<?php
include("script_file.js");
?>
And also if you want get only the js part of the second file use something like this
<?php
$Vdata = file_get_contents('path/to/YOUR/FILE.php');
preg_match_all("'<script(.*?)</script>'si", $Vdata, $match);
foreach($match[1] as $val)
{
echo $val;
}
?>
I have some pages that I don't want users to be able to access directly.
I have this function I came up with which works:
function prevent_direct_access()
{
if($_SERVER['REQUEST_URI'] == $_SERVER['PHP_SELF'])
{
//include_once('404.php');
header("Location: 404.php");
}
}
This does exactly what I want, the URL does not change but the content does. However I am wondering if there is something I need to add to tell search engines that this is a 404 and not to index it. keep in mind I do not want the URL to change though.
Thanks!
Don’t redirect but send the 404 status code:
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found', true, 404);
exit;
for the search engines, if you return HTTP status 404 they should not index I believe. But you could always redirect to somewhere covered by a robots.txt
Just to clarify:
You have some PHP that you want available to other PHP programs on the system
You do not want anybody accessing it except by running one of the other PHP programs
(i.e. "direct" doesn't mean "except by following a link from another page on this site")
Just keep the PHP file outside the webroot. That way it won't have a URL in the first place.
To ensure Search Engines don't index it, use a header() command to send a 404 lke this;
header("HTTP/1.0 404 Not Found");
Or put all such files in one folder, "includes" say, and add a "Deny /includes/" into your robots.txt file. This way, you can also add a ".htaccess" file in the same directory with one line - "Deny From All" - this will tell Apache to block access (if apache is configured properly), for another layer of security.
I want to hide file links generated by php function in source code. I know its impossible to hide source code but i think there should be a way to hide php generated links in php code.
Here is the part of my code which used to generate links.
<?php foreach($tracks as $track){ ?>
<tr class="track"
data-track_order="<?php echo $track['menu_order']; ?>
"data-track_src=" <?php echo $track['audio_file']; ?>">
OUTPUT IN SOURCE
<tr class="track" data-track_order="2" data-track_src="http://domain.com/spins.mp3">
Is there any way in javascipt or in php vulnerability to make this hidden in source?
Well, From the above code, i tried so many encryptions methods but none of them worked.
I need any solution to make it hidden in source.
There are ways to try to get around this topic BUT the browser NEEDS to see the plain html code in order to render the webpage. Because of this current methods can be easily circumnavigated and they client will still be able to get hold of the link. So you can never fully stop the client getting your links BUT you can make it harder for them to get at it by using some techniques like javascript Obfuscation.
I presume that you want to hide the location so that people can't just retrieve the file without going through your site?
Instead of serving the file directly, have a php file serve the file. This file can then check that you are logged into the system, or have a time limited auth key that was generated from the page, whatever you think may limit the ability to copy and paste the link.
If the client accessing the file doesn't pass the checks, you serve them an authorisation failure header instead of the file contents.
What is the purpose of hiding the link? To stop people from being able to see the file location, or to stop anything other than your application from accessing the MP3's?
You can program the link into your JavaScript and obfuscate it which will make it hard for the end user to see the link but ultimately its impossible to complete hide it if you are sending the end user to that page.
If you want to simply stop people from accessing the MP3 location(s) you might be better off looking at putting a .htaccess / mod rewite on the directory that they are residing in, or, have a single .php page to load in the MP3's that will authenticate the referrer and/or server IP address before loading the required file.
I've been looking around for quite some time now and I cant seem to find a way to get a list of subfolders from a specific directory.
An example would be, if I'm at www.mysite.com/projects and inside projects there are several folders containing individual project files.
the reason I want to do this is I was going to make a script that would add new project's names to a menu using the sub folder names.
Am I missing something ? Is this even possible with JQuery or JavaScript ?
I've gone as far as getting pathnames and locations and also had a look at ActiveXObjects but cant get anything to work on either my PC or on the server.
Any help would be appreciated.
There is no such thing as a directory in HTTP. Only resources.
Some of those resources might be an HTML document that lists some other resources (which are in a particular directory on a file system on a computer running the HTTP server). Most HTTP servers will generate such documents for you automatically.
You need to have your server generate a suitable response for a suitable request. Then use (since you mention jQuery) the ajax() method to make that request.
Then you need to parse the response. You can either use the default directory index page and then parse the HTML returned, or you can write a server side program to generate the data in a nicer format (such as JSON).
That said…
the reason I want to do this is I was going to make a script that would add new project's names to a menu using the sub folder names.
You would almost certainly be better off doing that on the server. You'll get more reliable, faster and search engine friendly results.
ActiveX is a technology enabling JScript (the Microsoft implementation of JavaScript) to have more access to the clients computer and it only works on Internet Explorer.
Folders on the server are not like folders in a filesystem. Any folder/subfolder has the potential to contain an index.html which outputs some text (not necessarily the list of subfolders it contains).
Also most webserver configurations have an active options of not showing the subfolder list even if there is not index.html present.
What you can do is place an index.php file in that folder with the following code:
<?php
$directories = scandir('.');
header('Content-Type: application/json');
echo json_encode($directories);
And you can receive this content as such:
$.getJSON('http://domain.com/path/to/folder/', function(directories) {
do_something(directories);//
});
I've got a site where individual pages might require some javascript or CSS files hooked into their heads. I'm trying to keep everything client side when it comes to managing this process, rather than getting on the FTP and sorting everything out in the code so I need to be able to upload css and js files.
I've got CCK filefield up and running, and it works with css files, but it refuses to upload .js files. It instead seems to view every .js as ".js.txt" and then the file appears on the server as thisismyfile.js.txt
Not ideal...
Does anyone know how to work around this. Is it a mime type problem with Drupal or the server, or is Drupal set up to avoid script uploads and n00b hack attacks.
Once the files are uploaded I intend to use PHP mode on the page or node to call drupal_add_css and drupal_add_js.
Looking at the field_file_save_file() function in field_file.inc from filefield module, you can find the following snippet
// Rename potentially executable files, to help prevent exploits.
if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
$file->filemime = 'text/plain';
$file->filepath .= '.txt';
$file->filename .= '.txt';
}
So yes, it's a 'security thing', as Jeremy guessed.
You could patch that RegEx for an immediate 'fix', but that would remove this otherwise useful security check completely for all filefields used on the site.
So a more specific workaround might be a better approach. Since you want to add the files via drupal_add_js() calls from code anyways, you might as well do the renaming there, adding some kind of verification to make sure you can 'trust' the file (e.g. who uploaded it, whatever).
Edit: Concerning options to rename (and alternatives) when calling drupal_add_js():
For renaming the file, look into the file_move() function. A problem with this would be that it won't update the corresponding entry in the files table, so you would have to do that also, if the move operation succeeded. (The filefield just stores the 'fid' of the corresponding entry in the files table, so you'd need to find it there by 'fid' and change the 'filename', 'filepath' and 'filemime' entries according to your rename/move)
Alternatively, you could just load the content of the *.js.txt file and add that string with the 'inline' option of drupal_add_js(). This would be less 'elegant' and could be a performance hit, but if those are not important criteria in your specific case, it is less trouble.
Yet another option would be just passing the *.js.txt file as is to drupal_add_js(), ignoring the 'wrong' extension. A short local test showed that this works (at least in firefox). This might be the 'least effort' solution, but would need some additional testing concerning different browser behavior concerning usage of 'misnamed' js files.
Allowing Drupal to upload javascript files would be a security risk, which is also why it doesn't allow you to do it, but instead appends the .txt extension. The reason is that js files are executable along with php, pl, py, cgi, asp. So if Drupal could upload those files to the server, it would be possible for evil doers to upload a file and run it doing all kinds of nasty things on your server, basically anything is possible. Best thing would be to find a different way of uploading files which are secure.
I had a similar need, and found a way to get around the security by first changing the 'allow_insecure_uploads' variable value by running this line of code in your hook_install:
variable_set('allow_insecure_uploads', 1);
Then in a module add this function
/**
* Implementation of FileField's hook_file_insert().
*/
function MODULE_NAME_file_insert(&$file) {
//look for files with the extenstion .js.txt and rename them to just .js
if(substr($file->filename, -7) == '.js.txt'){
$file_path = $file->filepath;
$new_file_path = substr($file_path, 0, strlen($file_path)-4);
file_move($file_path, $new_file_path);
$file->filepath = $file_path;
$file->filename = substr($file->filename, 0, strlen($file->filename)-4);
$file->filemime = file_get_mimetype($file->filename);
$file->destination = $file->filepath;
$file->status = FILE_STATUS_TEMPORARY;
drupal_write_record('files', $file);
}
What this does is in the hook_insert call it checks if a file has the extension ".js.txt". If it does it copies it to a new location and renames it. This is after the security check so its ok. I don't think you need to worry about the cache clear deleting your js files as long as you don't put them in the files/js directory. Create your own directory for you module and you should be ok.
I faced this situation when I wanted to allow .js file to be upload as is (without .txt and with 'application/javascript' mimetype) for a specific field. Also, I didn't wanted to alter Drupal core... of course.
So I needed to create a module implementing hook_file_presave(). This also work for Multiupload File Widget, since its hook is on file_save().
Note that you would have to replace MYMODULE_NAME and MYFIELD_NAME by your own values.
function MYMODULE_NAME_file_presave($file) {
// Bypass secure file extension for .js for field_additional_js field only
if((isset($file->source) && strpos($file->source, "MYFIELD_NAME") !== FALSE) && substr($file->filename, strlen($file->filename) - 7) == ".js.txt") {
// Define new uri and save previous
$original_uri = $file->uri;
$new_uri = substr($file->destination, null, -4);
// Alter file object
$file->filemime = 'application/javascript';
$file->filename = substr($file->filename, null, -4);
$file->destination = file_destination($new_uri, FILE_EXISTS_RENAME);
$file->uri = $file->destination;
// Move fil (to remove .txt)
file_unmanaged_move($original_uri, $file->destination);
// Display message that says that
drupal_set_message(t('Security bypassed for .js for this specific field (%f).', array('%f' => $file->filename)));
}
}
Drupal also "munges" javascript files. To prevent Drupal from automatically adding underscores to the filename there is a hidden variable that is checked before the filename is "munged".
Setting the variable to 1 solves the issue for me (along with altering the REGEX in includes/file.inc).
I hate hacking core, but this seems like a poor design to me. Javascript files are not server side scripts like php, py, pl, cgi, and asp.
You can use the allowed file extensions settings to prevent php and other server side scripts from being uploaded.
eg:
variable_set('allow_insecure_uploads', 1);
See:
http://api.drupal.org/api/function/file_munge_filename/6
So uploading .js files to the files directory is pretty much impossible.
Even if you manage to get .js files uploaded cleanly, these files will get deleted when the cache is cleared.
Any js files that live inside the files directory will be deleted whenever the drupal_clear_js_cache() function is executed.
http://api.drupal.org/api/function/drupal_clear_js_cache/6
So Drupal sees .js files living in the file uploads directory as temporary.
Now I understand why they are appending ".txt", it is to prevent them from being removed when the cache is cleared.
So as a compromise I guess I will just be uploading .js files manually (via FTP) to the /misc folder. :(