How can I secure use of fopen on a CSV file? - security

I have a PHP script which allows a user to upload a CSV, and then make some changes via an API.
I use fopen to open and access the file after it's been uploaded. I check for size, name, presence of known bad extensions etc using the $_FILES array on upload.
The data is simply a grid of ID's and corresponding action codes.
It's a closed group of users, and nothing is being include)()'ed or require()'d from this input but I am still concerned that by manipulating the upload something bad can happen.
if (($han = fopen($fileloc, "r")) !== false) {
while (($data = fgetcsv($han, 50, ",")) !== false) {
array_push($stack, $data); //
}
fclose($han);
}

The only thing I could see is when echoing back HTML (echo or print) use: htmlspecialchars just to be on the safe side
Hope that helps! ^_^

Related

Node.js read file, if exist append data, if not exist create file

I try using fs.open(). But when the file not exist, the data exist.
Below is my code:
fs.open('person.json', 'w', function (err, data) {
if (err) throw err;
console.log(data)
});
console.log(data) result is
3
Why is that? Where the 3 come from?
My purpose is to read the file if exist and create new file if doesn't exist. How to do it in node.js?
It sounds like the FIRST thing you want to do is call fs.statSync(), to check if the file exists.
If it exists, then call fs.open("r"), to read it.
Otherwise, it sounds like you want to create it. fs.open("w"), as you've done above, should work fine.
fs.open returns a file descriptor. I suspect that's probably the "3" you're asking about.
Addendum 4/24/19
Historically speaking (other languages, other times), the idea of using "exceptions" to handle "control flow" is frankly HORRIFYING.
But repeatdomiau makes a valid point. The documentation does seem to suggest simply opening the file, and handling any exception that might arise:
https://nodejs.org/api/fs.html
// Check if the file exists in the current directory, and if it is writable.
fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => {
if (err) {
console.error(
`${file} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`);
} else {
console.log(`${file} exists, and it is writable`);
}
});
Using fs.access() to check for the accessibility of a file before
calling fs.open(), fs.readFile() or fs.writeFile() is not recommended.
Doing so introduces a race condition, since other processes may change
the file's state between the two calls. Instead, user code should
open/read/write the file directly and handle the error raised if the
file is not accessible.
'3' - is a file descriptor.
https://nodejs.org/api/fs.html#fs_file_descriptors
'w' - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
Use 'r+' - Open file for reading and writing. An exception occurs if the file does not exist.
https://nodejs.org/api/fs.html#fs_file_system_flags
you can use "ax" mode means Open for appending. If the file does not exist, it is created but the file is opened in exclusive mode.
or can use "a+" mode means Open for reading and appending. If the file does not exist, it is created
and '3' you are getting is a file descriptor ("On POSIX systems, for every process, the kernel maintains a table of currently open files and resources. Each open file is assigned a simple numeric identifier called a file descriptor."
At the system-level, all file system operations use these file descriptors to identify and track each specific file. Windows systems use a different but conceptually similar mechanism for tracking resources. To simplify things for users, Node.js abstracts away the specific differences between operating systems and assigns all open files a numeric file descriptor.
The fs.open() method is used to allocate a new file descriptor. Once allocated, the file descriptor may be used to read data from, write data to, or request information about the file.)
Try to check this code, It might work for you
const fs = require('fs');
const readline = require('readline-sync');
// Check if the file exists in the current directory, and if it is writable.
var path = ("file.txt"); // Path to your file
var data = output; // this variable contains some data to insert
fs.access(path, fs.constants.F_OK | fs.constants.W_OK, (err) => {
if (err) {
fs.writeFileSync('file.txt', output, 'utf-8'); //create a new file
} else {
try {
fs.writeFileSync(path, data, {flag:'a+'}); //append mode: adds text to actually existing file
} catch(err) {
console.error(err); //shows error if script can't add data
}
}
});
Also you must install readline-sync module from npm, also change 'path' and 'output' variables to make this work. After this if you will don't have file, script make a new one, if will exist, will insert actual data to your file without reseting it.
P.S: Sorry for my English language.

X-Pages: fileUpload control preventing unwanted files from being uploaded

I am using the accept property in the fileUpload control to only allow certain file Types and prevent uploading .exe or other potentially harmful files.
application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/pdf,text/plain,image/gif,image/jpeg,image/pjpeg,image/png"
This works, however I am using a Tool called Burp Suite that allows me to intercept an acceptable file eg .txt that could contain harmful code and change the filename extension to .exe which is then upload to the X-Page database.
When I goto save the document and after Interception and changing to a .exe, I have added the following code to identify an exe file:
Can we manipulate what has been uploaded and change the file extension to a harmless .txt ?
var fileData:com.ibm.xsp.http.UploadedFile =facesContext.getExternalContext().getRequest().getParameterMap().get(getClientId('fileUpload1'));
if (fileData != null) {
var tempFile:java.io.File = fileData.getServerFile();
// Get the path
var filePath:String = tempFile.getParentFile().getAbsolutePath();
// Get file Name
var fileName:String = tempFile.getParentFile().getName();
// Get the Name of the file as it appeared on the client machine - the name on the server will NOT be the same
var clientFileName:String = fileData.getClientFileName();
}
var fileRight = clientFileName.slice(-4);
if (fileRight == ".exe")
{
//facesContext.getExternalContext().getRequest().getParameterMap().get(getClientId('fileUpload1').replace(".exe",".txt"))
//facesContext.getExternalContext().getRequest().getParameterMap().get(getClientId('fileUpload1').remove(".exe",0))
}
Yes, you can. You have on the properties of control two options 'Use original file name of uploaded file' and 'Replace file name of uploaded file...' where you can put name with extension 'name.txt' . I didn't try to change only extension... That is probably better in code to replace.

Where to initialize extension related data

am a newbie, trying to write some basics extension. For my extension to work i need to initialize some data, so what I did is inside my background.js i declared something like this.
localStorage["frequency"] = 1; //I want one as Default value. This line is not inside any method, its just the first line of the file background.js
Users can goto Options page and change this above variable to any value using the GUI. As soon as the user changes it in UI am updating that value.
Now the problem is to my understanding background.js reloads everytime the machine is restarted. So every time I restart my machine and open Chrome the frequency value is changed back to 1. In order to avoid this where I need to initialize this value?
You could just use a specific default key. So if frequency is not set you would try default-frequency. The default keys are then still set or defined in the background.js.
I like to do that in one step, in a function like this
function storageGet(key,defaultValue){
var item = localstorage.getItem(key);
if(item === null)return defaultValue;
else return item;
}
(According to the specification localstorage must return null if no value has been set.)
So for your case it would look something like
var f = storageGet("frequency",1);
Furthermore you might be interested in checking out the chrome.storage API. It's used similar to localstorage but provides additional functionalities which might be useful for your extension. In particular it supports to synchronize the user data across different chrome browsers.
edit I changed the if statement in regard to apsillers objection. But since the specification says it's ought to be null, I think it makes sense to check for that instead of undefined.
This is another solution:
// background.js
initializeDefaultValues();
function initializeDefaultValues() {
if (localStorage.getItem('default_values_initialized')) {
return;
}
// set default values for your variable here
localStorage.setItem('frequency', 1);
localStorage.setItem('default_values_initialized', true);
}
I think the problem lies with your syntax. To get and set your localStorage values try using this:
// to set
localStorage.setItem("frequency", 1);
// to get
localStorage.getItem("frequency");

How do you get the filename from the XPages FileUpload Control

In XPages, in the file upload control, after a user selects a file but before it's saved how can you get the filename? I'm not interested in the path as I believe that's not getable due to security issues but I would like to get the filename and extension if at all possible.
Thanks!
Actually you can get the file and fully manipulate it, read it, do whatever you want with it, its stored in the xsp folder on the server, to which you have read/write access... here is a code snippet that interacts with the file, I usually call from beforeRenderResponse...
var fileData:com.ibm.xsp.http.UploadedFile = facesContext.getExternalContext().getRequest().getParameterMap().get(getClientId('<INSERT ID OF UPLOAD CONTROL HERE (ie. fileUpload1)>'));
if (fileData != null) {
var tempFile:java.io.File = fileData.getServerFile();
// Get the path
var filePath:String = tempFile.getParentFile().getAbsolutePath();
// Get file Name
var fileName:String = tempFile.getParentFile().getName();
// Get the Name of the file as it appeared on the client machine - the name on the server will NOT be the same
var clientFileName:String = fileData.getClientFileName();
}
It sounds like you are referring to needing to get the data via CSJS, which you can do with the following code:
var filename = dojo.byId('#{id:fileUpload1}').value.split('\\').pop();
These links should be able to help you.
http://www.bleedyellow.com/blogs/andyc/entry/intercepting_a_file_upload4?lang=en
http://www.bleedyellow.com/blogs/m.leusink/entry/processing_files_uploaded_to_an_xpage?lang=en

Is it possible to link a cell In Excel to a local file with a querystring?

I had wanted to put a solution onto a thumb drive or dvd to be distributed as needed. I have a couple html pages with javascript to display photos and some other info. I also have an excel spreadsheet (2003) that I wanted to link to the html page. However when I try to use a querystring I get a warning from excel stating that it "cannot open the specified file."
edit: I use javascript to parse the querystring and load a specific photo and some info.
This does not work:
=HYPERLINK("site_photos.htm?p=1", "photo 1")
This works:
=HYPERLINK("site_photos.htm", "photo 1")
Any help here would be greatly appreciated.
edit:
Okay, I've tried using ThisWorkbook.FollowHyperlink procedure using the extrainfo and not using the extrainfo parameter. This did not work. I also tried using a shell command. This also did not pass the querystring either. It looks like I will need another solution.
edit:
Here's the javascript function used to retrieve the querystring. The querystring is not in the window.location.href so this will not work when called.
function parseUrl(name)
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexStr = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexStr );
var results = regex.exec(window.location.href);
if( results == null )
return "";
else
return results[1];
}
Whether it is possible to perform the original task or not, I have opted for a different solution. I will use image controls to view the photos and other controls for navigation.

Resources