ServiceStack: Serve static files with extension docx and zip - servicestack

I have in the root of my web application two files: file1.docx and file2.zip neither of these files are served and instead I receive a 403 error. If I change the extension to .txt then the file gets served with no problem which leaves me to believe that SS looks at the extension?
.docx and .zip are in IISs list of known MIME types so I'm not sure why SS would serve the one and not the other as I thought the only check was that a physical file existed at that location.

Right, you need to add it to the Config.AllowFileExtensions safe whitelist, e.g:
SetConfig(new EndpointHostConfig {
AllowFileExtensions = { "docx", "zip" }
});

Related

Blazor server app cannot download .msg files

I have a Blazor Server 6.0 app where I have links to download .msg files.
I have setup IIS to serve that mime-type trying both application/octet-stream and application/vnd.ms-outlook (and restarting IIS)
I have also tried to put in web.config the staticcontent tag like suggested here:
.msg file gives download error
And obviously in my program.cs I have app.UseStaticFiles();
I try to put the .msg in a non-blazor app and they work ok, so I think is not IIS related
So why I cannot download (or open automatically in outlook) this type of file, while other (docx, pdf, zip, etc.) are Ok ?
ASP.NET Core -- on the server side -- also needs to know about the files it has to serve. You can enable serving all unknown file types (I'd rather not include the relevant code as it is a major security risk), or you can add you own additional mappings like so:
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".msg"] = "application/vnd.ms-outlook";
// app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider
});
More info in the official docs: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-7.0#fileextensioncontenttypeprovider
Additionally, Blazor Server registers custom options for serving static files (like .server.js, which is different from just .js). It's not directly exposed as a public API to configure, but you can look at the source here as to what the AddServerSideBlazor extension method actually does. The solution there relies on you calling UseStaticFiles without explicitly specifying the options, so that it can retrieve the StaticFilesOptions instance from DI.
Armed with this knowledge, you can override an already configured options instance as follows:
builder.Services.PostConfigure<StaticFileOptions>(o =>
{
((FileExtensionContentTypeProvider)o.ContentTypeProvider).Mappings[".msg"] = "application/vnd.ms-outlook";
});
This configures the already initialized options instance registered in the DI (after all other configurations happened on it, thus PostConfigure).
Note that if you would for whatever reason decide to use a different IContentTypeProvider, the unsafe cast above would need to be revised as well.

Next.JS security of directory structure and JSON secrets

I have a security question regarding the access of Next.JS directories, and their access requirements. I have a root folder that has my pages, public, src, styles, models folders. In the src folder I have a settings.json file that is a empty JavaScript object. The idea is that settings would be added to this file and accessed by api routes, to check settings that could be modified on this settings.json file... What I am wondering is if the client can actually somehow just read/access the src directory and get the settings.json file. I want to put secret key's here that way I can easily change secret keys without having to restart my server. So I could just update the secret key live, and have it applied to the settings.json file. Then the update would be live immediately and I don't have to change the environment variables and restart the server.
Is it safe to keep and use a json file in the src directory to store confidential data? If not, is there a way to keep and use a json file for this purpose?
Thanks for the help and info.
As juliomalves pointed out client code won't be able to access a directory or file that you have on the server with the exception of the public directory.
Next gives you the ability to serve static assets from [root]/public as documented here
Note: Only assets that are in the public directory at build time will be served by Next.js.
If this directory is ever renamed, these assets are no longer available from a client.
Note: Don't name the public directory anything else. The name cannot be changed and is the only directory used to serve static assets.
"I put a settings.json file right next to that .env file and required it in an api route, could the client somehow download that settings.json file without me purposely sending them the contents/file itself?"
The only way information can be served from an api route is by expressly creating a route to call res[ponse].send() (or res.json()) with data imported from that file. Api routes are not ever bundled on the client side and only ever exist on the server as noted here.
Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.
"What I am wondering is if the client can actually somehow just read/access the src directory and get the settings.json file."
As noted above only assets in the /public directory are accessible as files by path. Directories are never accessible in Next as static assets. This is even pointed out in the source code.
send(req, path)
.on('directory', () => {
// We don't allow directories to be read.
const err: any = new Error('No directory access')
err.code = 'ENOENT'
reject(err)
})

Problem with FallbackRoute in Servicestack

I am using the Servicestack react template and I have noticed that in chrome I get errors in the console which indicate that the manifest.json is inaccessible. After some poking around, I believe the issue is with the fallbackroute.
Initially the template contains the fallbackroute as follows:
[FallbackRoute("/{PathInfo*}", Matches="AcceptsHtml")]
Which makes sense since manifest.json is not html so I can see why I get a 403 error.
However, after changing the route to:
[FallbackRoute("/{PathInfo*}", Matches = #"PathInfo =~ \/(index\.html|manifest\.json|favicon\.ico)$")]
Which to my understanding should match index.html or manifest.json or favicon.ico, still does not work. Index.html and favicon.ico work just fine, however I get a 'forbidden' error when requesting manifest.json which is strange because the file is in the same folder with the same permissions as the other 2 files.
What am I missing?
Any static files you want to allow need to be specified in Config.AllowFileExtensions, to allow access to .json static files, add the extension in your HostConfig, e.g:
SetConfig(new HostConfig {
AllowFileExtensions = { "json" }
});

Can the Virtual File System In Service Stack Be configured not not treat files with multiiple dots as directories?

I'm attempting to serve an angular spa from embedded resources using the ServiceStack Virtual file system.
This appears to be mostly working, however many of my generated files include two dots in the file name like:
inline.bundle.js
I expected that would be served from:
host:port/inline.bundle.js
but it is actually served from
host: port/inline/bundle.js
The virtual filesystem appears to namespace based on the dot. Is there a way to configure it other wise so multiple dots in the last file are not interpretted as directories?
I'm using the angualr-cli to build the app, and it does not expose a way to modify the webpack config generating the bundles, otherwise I would just modify the file names.
The issue is that Embedded Resources don't include paths when the file is embedded so a file in a folder like /inline/bundle.js is embedded with the same resource name that /inline.bundle.js is, i.e: AssemblyNamespace.inline.bundle.js and it's up to ServiceStack's ResourceVirtualDirectory to use common heuristics to predict what the folder is.
You can force the ResourceVirtualPathProvider to treat a file by specifying it in:
SetConfig(new HostConfig {
EmbeddedResourceTreatAsFiles = { "inline.bundle.js" }
});

controlled access of classified files in laravel-4

I've read that files in the public folder are accessible via a web browser in Laravel. When I type in the path to files in my public folder, I don't see the file, unless I defined the path in the routes.
I am making a downloads page so that a user can download encrypted/classified materials via a from.
I do not want the ability for a user to access the files in any other way other than the download form or other controlled methods.
Do I need to create lets say a private folder and store the files their. If I do, will I still have access to the files in the back end?
Or are files in the public folder not accessible unless defined by the routes? If thats right could I just store the files under public?
Files under public folder are accessible by anyone, unless your webserver has a policy set to a particular directory.
If you are currently not able to access a file in your public folder is because, maybe, you are not writing the url correctly, ie:
A file in
/var/www/myapp/public/img/logo.png
Will be accessible via:
http://myapp.com/img/logo.png
Note that the public part of your folder is not present in your URL ONLY IF your webserver is correctly configured and your .htaccess file is in place and able to rewrite your URL.
For sensitive files, what you can do is to store them insite your app folder (or any other folder outside public), where just your application will have access to, something like this can be ok:
/var/www/myapp/app/storage/<create a new folder here>
And then, yes, create a route to read and present your secure files:
Route::get('readfile/{fileName}', ['before' => 'auth', 'use' => 'ReadFileController#read']);
The filter 'before' => 'auth' will assure that one not authenticated will never be able to access a file.
In your controller you could do something like this to check if one can see a file:
class ReadFileController extends Controller {
public function read($fileName)
{
if(Auth::user()->id == 1) // of course this is not a good way, just an example
{
return $this->getFile($fileName);
}
else
{
return Response::make(null, 403); // forbidden
}
}
private function getFile($fileName)
{
...
}
}
Also, you can use authentication "middelware" in your routes to add better access control.
Route::get('routeName', ['middleware' => 'auth', 'uses' =>'XController#action']);

Resources