I am trying to develop a chrome extension that would set the "host" header on certain requests. But the documentation is contradicting as to if the "host" header can be modified or not.
Both of these issues indicate that a) it should not be possible and b) it is impossible
https://code.google.com/p/chromium/issues/detail?id=154900
https://code.google.com/p/chromium/issues/detail?id=158073
Yet multiple extensions in the gallery state they do modify the "host" header.
e.g.
https://chrome.google.com/webstore/detail/header-hacker/phnffahgegfkcobeaapbenpmdnkifigc?hl=en
https://chrome.google.com/webstore/detail/change-http-request-heade/ppmibgfeefcglejjlpeihfdimbkfbbnm
Is it possible to modify the "host" header in the windows version of chrome, and if so how?
Background: I want to be able to test load balanced web instances hitting each host directly via ip address. The "hosts" file is to cumbersome for a large number of hosts. At the moment I use curl to pass the modified "host" header, but I really need the solution in the browser and available for others.
#kzahel was right, and the note about redirection was spot on, here is my basic working code.
chrome.webRequest.onBeforeSendHeaders.addListener(function (details) {
if (details.url.indexOf('toast.txt') <= -1)
return;
details.requestHeaders.push({
name: 'Host',
value: 'testhost:80'
});
return { requestHeaders: details.requestHeaders };
}, {
urls: ['http://*/*']
}, ['requestHeaders', 'blocking']);
chrome.webRequest.onBeforeRequest.addListener(function (details) {
if (details.url.indexOf('sauce') <= -1)
return;
var url = 'http://127.0.0.1/toast.txt';
return { redirectUrl: url };
}, {
urls: ['http://*/*']
}, ['blocking']);
Admittedly a slightly odd example but it goes like this.
My local IIS has a site created that points to a folder that has a file "toast.txt", which is bound to "testhost".
Windows can no way of knowing about "testhost" e.g. cannot ping it.
With the extension running.
Enter the address http://testhost/sauce
The extension notes the "sauce" in the "onBeforeRequest" method and redirects to "http://127.0.0.1/toast.txt" which in turn is picked up on by the "onBeforeSendHeaders" method where the "Host" header is added containing "testhost:80". All this occurs before the request leaves Chrome.
Now IIS receives the request "/toast.txt" that by itself would result in a 404, but because the "Host" header is set it pushes the request to the new website that is bound to "testhost" which then returns the "toast.txt" file.
Phew!
It looks like you shouldn't have difficulty doing this. Use onBeforeRequest
onBeforeRequest: Fires when a request is about to occur. This event is sent before any TCP connection is made and can be used to cancel or redirect requests.
Since this is triggered before any connection to the server is made, you should be able to modify the host header then [edit: if host header is not available, then use a redirect]. Make sure you have the "requestHeaders" permission in the manifest or else you won't see the request headers at all.
Related
We have a cluster with 3 servers with Load Balancer in front (CloudFlare). Things worked well when we had 2 servers (A & B) in the cluster but after we added a 3-rd server (C) we noticed few odd things.
One of them is quite important and I do not understand how it happens at all.
Our web application makes AJAX requests to itself in order to get some JSON data back and if requests hit new server (C) response looks like that:
{
code: 404,
text: "Not Found",
message: "Database context not allowed."
}
Our application does not throw such error and so I searched in google a bit and noticed that it's mentioned on: OpenNTF XPagesExtensionLibrary
However, we do not use XPages at all so I wonder how could it be that our AJAX requests somehow involve that logic.
Any suggestion & tip would be appreciated.
UPDATE
The backend code of my agent is not important (it could be also an empty agent, I checked), because the request does not come to my agent.
The AJAX call is triggered by jQuery
let url = "domain.tld/api/key";
let params = {"a": 1};
$.post(url, params, function (data) {
// some code
},
"json"
).always(function() {
// some code
});
The URL, which I suspect is an issue starts with /api/key and I believe it's an issue (because all other ajax calls where endpoint do not start from /api/ work well).
Thanks.
Figured that our with help from comments (which you can see under my original post).
Apparently there is DAS servlet that handles all requests starting from /api/* and it runs if XPages engine is loaded.
In my case the 2 servers out of 3 have XPages shut down so the issue happened only on 1 server.
The solution would be:
Shut down XPages (or find a way to shut down DAS).
Alternatively change a URL from /api/path to something else (this is what we will do).
I found chrome.declarativeNetRequest only supports static rules, What I want is to call some custom methods before actions like redirect/request. I haven't found a solution so far. I'm not sure if I can still do this under the Manifest V3.
There are two usecases for my extension.
Before the redirect, I need to execute custom method.
chrome.webRequest.onBeforeRequest.addListener(
function(requestDetails) {
//
// I can get id from requestDetails.url,
// then do some custom business logic.
//
custom_function(requestDetails.url);
return {redirectUrl:"javascript:"};
},
{urls: [ "url_pattern?id=*" ]},
["blocking"]
);
Before some request, I want add/modify requestHeaders according to the user's browser.
chrome.webRequest.onBeforeSendHeaders.addListener(
function (details) {
details.requestHeaders.push({
"name": "User-Agent",
"value": navigator.userAgent + "version_1.0.0"
});
return {requestHeaders: details.requestHeaders};
},
{
urls: ["*://url_pattern"],
types: ["xmlhttprequest"]
},
["blocking", "requestHeaders"]
);
#wOxxOm Thank you very much for your patient answer !
I prefer to spinner.html. But I have another problem.
I can't set the regexSubstitution to the extension address,
I can use the extensionPath, but the corresponding capture groups doesn't work here.
"regexFilter": "google.com*"
The following are all incorrect:
can't use the corresponding capture groups.
"extensionPath": "/spinner.html?url=\\0"
can't use the extension's address.
"regexSubstitution": "spinner.html?url=\\0"
Is my configuration incorrect?
Adding/deleting headers can only accept static values and it's shown in the official example.
Conditionally adding/deleting/modifying headers based on response headers is tracked in https://crbug.com/1141166.
Nontrivial transformations that exceed the functionality of the actions listed in the documentation naturally cannot be re-implemented.
When https://crbug.com/1262147 is fixed we will be able to define a declarativeNetRequest rule to redirect to a page inside your extension via regexSubstitution or extensionPath and append the original URL as a parameter. This page will act as an interstitial, it will display some kind of UI or a simple progress spinner, process the URL parameters, and redirect the current tab to another URL.
In many cases this approach would introduce flicker and unnecessary visual fuss while the interstitial is displayed shortly, thus frustrating users who will likely abandon using such extensions altogether. Chromium team members who work on extensions seem to think this obscene workaround is acceptable so it's likely they'll roll with it, see also https://crbug.com/1013582.
Use the observational webRequest (without 'blocking' parameter) and chrome.tabs.update to redirect the tab. The downside is that the original request will be sent to the remote server. And this approach obviously won't work for iframes, to redirect those you'll have to inject/declare a content script, to which your webRequest listener would send a message with a frameId parameter.
Keep a visible tab with an html page from your extension, and use the blocking chrome.webRequest inside its scripts. It's a terrible UX, of course, even though endorsed by the Chromium's extensions team, with many extensions using this kludge the user's browsers will have to keep a lot of such tabs open.
P.S. The blocking webRequest will be still available for force-installed extensions via policies, but it's not something most users would be willing to use.
I am having issues after I changed the subdomain of my app, it was working the day before but now it doesn't it shows me the message
OneSignal: Could not load iFrame with URL
https://acacito.onesignal.com/webPushIframe. Please check that your
'subdomainName' matches that on your OneSignal Chrome platform
settings.
<script>
var OneSignal = window.OneSignal || [];
var OneSignal = window.OneSignal || [];
OneSignal.push(["init", {
appId: "MyAppID", // copied correctly the UUID
autoRegister: false, /* Set to true to automatically prompt visitors */
subdomainName: 'acacito',
httpPermissionRequest: {
enable: true
},
notifyButton: {
enable: true /* Set to false to hide */
}
}]);
</script>
I have been trying to make it work deleting cookies or any data related that could be stored in the browser and it doesn't work. Also reloading with Ctr+Shift+r, not sure what happens.
At the time of this writing, this error can occur if:
The Site URL in your onesignal.com dashboard settings does not begin with the same URL you're using to access your site.
For example, if your dashboard platform setting's Site URL is http://my-site.com, you have to access your site beginning with the URL http://my-site.com. You can access http://my-site.com/page1, and you can access http://my-site.com/folder/page2, but you have to begin with http://my-site.com. Technically, the Site URL is the origin your OneSignal configuration is allowed to run under, and OneSignal doesn't allow any other site origin from initializing OneSignal with the same subdomain.
For more complicated cases:
If you're developing locally on http://localhost:8181, your Site URL should also be http://localhost:8181 (with the port number).
If you have an alias defined in your hosts file, you still have to use the origin specified in your Site URL. The OneSignal web SDK looks at what's on the address bar and compares it to what's in the Site URL textbox.
The value for subdomainName (in this case acacito) does not match the value you chose in your onesignal.com dashboard settings for Chrome web push.
Just be sure to use the same value.
The app I'm working on has a controller that issues templates to the front end (single page app). It's very basic, and simply consists of
#path = params[:path]
render template: "templates/#{#path}", layout: nil
Here my concern however is the direct use of the users input. Everything about this to me feels like it can be attacked with something as simple as path traversal. The route for this is
get "/templates/:path.html" => "templates#file", constraints: { path: /.+/ }, defaults: { format: 'html' }
I've tried multiple things to attempt a path traversal attack, such as
request /templates/path/to/../somewhere/else.html
request /templates?path=/path/to/../../something.rb
request /templates/index.html?path=/path/to/../../config/something.html
request /templates/path/../../../file.html
Fortunately, I haven't had any success with this. The requests that just start with /templates and don't specify anything after it, don't match the route thanks to the constraint so that is good.
It seems as though when that route is matched, rails doesn't allow you to override the path parameter through a url parameter, so I don't seem to be able to inject it there.
The ones that interest are the first and last examples above, where rails seems to internally be changing the requested URL before invoking the routes file. When I request /templates/path/to/../somewhere/else.html, my console output shows a request for /templates/path/somewhere/else.html. When I make a request for /templates/path/../../../file.html, the log shows a request for /file.html.
Am I missing something somewhere that will leave the app open to security issues, or is this just rails being sensible and protecting itself for me?
UPDATE
I've done some more digging, and if I try doing some URL encoding then I can cause the server to simply not respond at all. If I request /templates/%2e%2e%2f%2e%2e%2f%2e%2e%2ffresult.html then I just get an empty response with a connection: close header.
I assume that the parameter parser higher up in the rack is checking all urls for this type of attack? Regardless, my original question still stands. Am I missing something here?
I am trying to append few extra parameters to the url that user typed (before the page gets loaded). Is it possible to do?
For example, if user types www.google.com, I would like to append ?q=query to url (final: www.google.com?q=query.
Thanks
The webRequest API might be what you need. This code goes in your background page:
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if( details.url == "http://www.google.com/" )
return {redirectUrl: "http://www.google.com/?q=defaultquery" };
},
{urls: ["http://www.google.com/*"]},
["blocking"]);
This is an extremely specific rule that redirects visits to http://www.google.com/ with http://www.google.com/?q=defaultquery, but I think you can see how to expand it to include more functionality.
Note that this will reroute all attempts to reach http://www.google.com/, including Ajax requests and iframes.
Per the documentation, you will need to add the webRequest and webRequestBlocking permissions, along with host permissions for every host you plan to intercept:
"permissions": [
"webRequest",
"webRequestBlocking",
"*://*.google.com/",
...
],
This is an old question still I am answering it for future readers.
Modification of query parameters is a little tricky because you can endup in an infinite loop and Chrome/Firefox may detect it and process whatever is the current state of the request URL.
I have faced this situation in my chrome extension Requestly where Users used Replace Rule and replaced www.google.com with www.google.com?q=query or did something similar.
The problem with this approach is browsers intercept the request URL after adding query parameter so the parameter will be added multiple times and corrupt the URL. So you have to ensure either of the following:-
Do not intercept a request once it has been redirected.
Check if the parameter already exists, then do not redirect it.
As correctly pointed out by #apsillers in his answer, you have to use webRequest API to perform any modifications to the URL. Please have a look at his answer
and write your code accordingly.
Just in case, you are looking for an already available solution, consider trying Requestly's Query Parameter Rule. Here is a screenshot of how it looks like:-
For Firefox, you can download Requestly from its home page.