I have a Blazor server-side app and I added the following the <head> of _Host.cshtml:
<meta http-equiv="Content-Security-Policy"
content="base-uri 'self';
default-src 'self';
img-src data: https:;
object-src 'none';
script-src 'self';
style-src 'self' 'unsafe-inline';
upgrade-insecure-requests;">
I originally all the hashes that were reported in the console. But the errors are still reported. I had to remove the hashes and add unsafe-inline. I'd rather have the hashes instead.
What am I missing?
Most likely the hashes are for inline event attributes such as onclick, onload etc. These can't be hashed, but the browser provides them in the errors anyway. You will need to rewrite with event listeners.
Related
A client wants us to add a script-src security policy to our software so that it satisfies their security standards. I have managed to create a relatively secure policy that still allows our code to run... EXCEPT I am getting a console error in my browser that says "Refused to execute inline script because it violates the following Content Security Policy directive" and that points to the file jquery-3.5.1.min.js. The error doesn't give me any more useful details. (It doesn't indicate a specific line in our code as being the problem.)
From what I can tell from the jQuery message boards, this sort of problem was fixed in jQuery several versions ago, so I have no idea why it's happening in this case.
I've also seen that some people access jQuery from a remote URL so the fix is to simply add that URL to script-src, but the current plan is to keep accessing jQuery from a local file.
I need to figure out how to stop getting this error without just making the code so unsafe that it defeats the purpose of using script-src in the first place (at which point the code would probably just fail the client's security scan again).
My current approach to the script-src policy has been to use a nonce. AFAIK, the nonce can't be generated by or brought into Web.config, so the only CSP in Web.config is this:
<add name="Content-Security-Policy" value="object-src 'none';" />
The Configuration() method inside Startup.cs calls another method called ConfigureNonce(), which is what creates the nonce and establishes the script-src policy:
private void ConfigureNonce(IAppBuilder app)
{
app.Use((context, next) =>
{
var rng = new RNGCryptoServiceProvider();
var nonceBytes = new byte[32];
rng.GetBytes(nonceBytes);
var nonce = Convert.ToBase64String(nonceBytes);
context.Set("ScriptNonce", nonce);
context.Response.Headers.Add("Content-Security-Policy",
new[] { string.Format("script-src 'self' 'unsafe-eval' xxxxxx yyyyyy http://localhost:* 'nonce-{0}'", nonce) });
return next();
});
}
'xxxxxx' is the URL of an external provider we use for a certain widget.
'yyyyyy' is the URL of our help documentation.
'unsafe-eval' is apparently necessary because we use Kendo. [Thanks, Kendo...]
'localhost' is apparently necessary in development to stop getting a script-src violation due to Browser Link, but it will need to be removed when we go to production. [Thanks, Visual Studio...]
Finally, I have made a new helper file called NonceHelper.cs that just contains this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace dTIMSi.Helpers
{
public static class NonceHelper
{
public static IHtmlString ScriptNonce(this HtmlHelper helper)
{
var owinContext = helper.ViewContext.HttpContext.GetOwinContext();
return new HtmlString(owinContext.Get<string>("ScriptNonce"));
}
}
}
All of this enables me to see what web browser console errors I get for inline scripts (there are a lot), go to whatever line of code each error is indicating, and just add the nonce, like so:
<script type="text/javascript" nonce="#Html.ScriptNonce()">
//bla bla bla, doin' some inline script stuff
</script>
Hopefully that all makes sense and is OK. But why am I getting an error on the jQuery file and how can I fix it?
I have a problem with Google's crawling and I am not sure if its a technical problem. Basically we redesigned our site a bit so we 301-redirect users like this:
url.com/ --> url.com/en/items or
url.com/en --> url.com/en/items
So every user ends up at the page url.com/lang/items
As recommended we use
<link rel="alternate" hreflang=
to tell Google where to find the shown page in another language.
eg:
http://www.url.com/en/boats has the tag:
<link rel="alternate" hreflang="de-DE" href="http://www.url.com/de/boote" />
and on http://www.url.com/de/boote its:
<link rel="alternate" hreflang="en-US" href="http://www.url.com/en/boats" />
Now, the crawler gives us the crawl errors "No backlinks" for url.com/en and url.com/de/items. Of course url.com/de/items links back to url.com/en/items, since url.com/en does not exist anymore. Why is the page url.com/en even considered here?
I redirect like this:
Response.Redirect(site);
Response.StatusCode = 301;
Response.End();
Any hint greatly appreciated!
Thanks!
Michael
with theses information its hard to say, if something is maybe missconfigured.
Could you pleaese add the exact lines of code for the tags for both pages?
Did you add also the line for the page itself, described in this article https://moz.com/learn/seo/hreflang-tag . This was an issue we had while implementing the hreflangs, and we got exactly the same errors.
It could also be that the google crawler has not yet indexed the "new" sites with the new urls, so it has still the old urls indexed. This could take a bit time, mentioned in this discussion https://www.quora.com/How-long-does-it-take-Google-recognize-301-redirect-updates-and-remove-the-old-pages-from-its-index
So I've created a Web Application (not Web Site) with ASP.NET (C#) and it compiles just fine in the VS13 environment. But when I publish it on IIS, the Postback on the Default Document fails. The Default Document is called LoginPage.aspx. As soon as I click the <asp:Button> to run my code behind, all it does is refresh the page. This project has been published on my local 127.0.0.1 IP address for the time being.
I know this has been a documented issue, but I've tried many solutions and have not come across a resolution. Some solutions I have attempted:
Creating a brand new Web App with minimal code to attempt accessing any Postback with no success.
I tried the first solution presented here with no success: https://stackoverflow.com/a/7367076/4204026
I also tried URL mappings:
<urlMappings>
<add url="~/login" mappedUrl="~/Views/LoginPage.aspx" />
<add url="~/login/" mappedUrl="~/Views/LoginPage.aspx" />
</urlMappings>
I'm honestly at a loss as to what's happening here. One thing I did notice is when the application is being run through Visual Studio, the <form> tag on the LoginPage.aspx appears in Chrome as:
<form method="post" action="LoginPage" id="ct101" class=".myForm">
Through IIS:
<form method="post" action="./" id="ct101" class=".myForm">
Not sure if that's a problem either. I tried hard-coding the action to login to see what would happen and it does redirect to the correct page, but as suspected no Postback was fired - My Session variable returned null and no query string was used.
Here's the related LoginPage.aspx front-end code (trimmed out a bunch of unrelated HTML):
<%# Page Title="DREW KENNEDY | WELCOME" Language="C#" MasterPageFile="Site.Master" AutoEventWireup="true" CodeBehind="LoginPage.aspx.cs" Inherits="MyMedia.Views.LoginPage" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<!-- form is located on Site.Master -->
<asp:Button OnClick="LoginBtn_Click" CssClass="login" runat="server" name="submit" Text="Sign In" />
</asp:Content>
And the LoginBtn_Click method in LoginPage.aspx.cs:
protected void LoginBtn_Click(object sender, EventArgs e) {
//Tried the following line while commenting out everything else to make sure Postback is being ignored
//Response.Write("<script>alert('Test');</script>");
try {
AbstractPersistenceDecorator decorator = new PersistenceDecorator();
string uname = username.Text.Trim();//username is a TextBox Control
string pass = password.Text.Trim();//password is a TextBox control
bool isCookieRequested = CheckBox.Checked;
if (decorator.authenticate(uname, pass)) {//calling SQL Server for authentication
User AuthenticatedUser = (User)Session["User"] ?? decorator.getUserInfo(uname);
if (Session["User"] == null) Session["User"] = AuthenticatedUser;
if (isCookieRequested) {
HttpCookie cookie = new HttpCookie("username", AuthenticatedUser.Username);
cookie.Expires.AddDays(7);
Response.Cookies.Add(cookie);
} else {
Session.Timeout = 15;
}
Thread.Sleep(1600);
//string redirect = string.Format("dashboard?username={0}", AuthenticatedUser.Username);
Response.Redirect("dashboard?username=" + AuthenticatedUser.Username);
}
} catch (Exception ex) {
//who cares?
}
}
Final pieces of info:
Running IIS 8.0
Application created with 4.5 Framework, Application Pool is also 4.5 Framework
I have ensured that ASP.NET is installed on IIS
I do have URL ReWriting in the global.asax file, though I'm not sure if that is related in any way (I don't see how).
I have no Default.aspx page
EDIT:
Just tested the project through 127.0.0.1 on IE11 and FF with the same result.
EDIT #2:
Additional things I have tried with no success:
I tried removing my URL Rewriting
I tried adding an empty URL Rewrite rule, i.e. ("Empty URL", "", "~/Views/LoginPage.aspx")
Additional notes:
I do not use Telerik
I do not use ISAPI
The project in Visual Studio was set to debug and not release
I apologize for not giving enough information in the OP as I have found the answer. It turns out it had nothing to do with ASP.NET, but rather SQL Server. I stripped the code bare and after adding back one piece of code at a time and stripping away all exception handling, I found through IIS that IIS APPPOOL\.NET vX.X did not have permissions to access the database.
What I had to do is:
In MSQLSM, add a new Login for IIS APPPOOL\.NET v4.5
Further on, I found out that it needed the correct permissions to perform certain commands after receiving the following exception:
The SELECT permission was denied on the object 'X', database 'X', schema 'dbo'
This Was Solved Here
Give that new Login the proper access. Login Properties > User Mapping > checking db_datareader and public.
The code behind now executes. It still leaves the question why it was prohibiting any Postbacks, even if I removed any SQL Connectivity in the code behind. Very strange.
Anyway, thanks to those who helped.
I suggest that you redirect from the default page to the Expected page then this should work. Iis default page handling is done through isapi to handle static content so the post data may not survive
Using C# MVC .NET 4.5 with my RouteConfig.cs set to append trailing slashes and convert URLs to lower case:
routes.AppendTrailingSlash = true;
routes.LowercaseUrls = true;
I have the following canonical link tag in the HTML of my views:
<link rel="canonical" href="#Url.Action("Index", Html.GetTitleType(Model.TitleType), new { i = Model.Title.Title_Id }, Request.Url.Scheme)" />
This works great but needs some modification. My preferred canonical URL structure is "http://www.example.com/something/1234/" - If I'm however browsing the site at "http://example.com" then the canonical link rendered is "http://example.com/something/1234/" which totally defeats the purpose. How can I ensure the canonical tag contains "http://www" no matter what? I could obviously hardcode the URL structure myself, but would prefer a more elegant solution.
Update: the best I could come up with is this:
<link rel="canonical" href="#string.Format("{0}{1}", "http://www.example.com", #Url.Action("Index", Html.GetTitleType(Model.TitleType), new { i = Model.Title.Title_Id }))" />
"http://www.example.com" could also be stored as a key-value pair in web.config so that the final result looks like this:
<link rel="canonical" href="#string.Format("{0}{1}", #System.Web.Configuration.WebConfigurationManager.AppSettings["canonical_root_URL"], #Url.Action("Index", Html.GetTitleType(Model.TitleType), new { i = Model.Title.Title_Id }))" />
Your provided answer:
<link rel="canonical" href="#string.Format("{0}{1}", #System.Web.Configuration.WebConfigurationManager.AppSettings["canonical_root_URL"], #Url.Action("Index", Html.GetTitleType(Model.TitleType), new { i = Model.Title.Title_Id }))" />
...will work fine as it will match scenarios such as http://example.com/something/1234, www.example.com/something/1234, http://example.com/something/1234?randomVar=5 and so on to http://www.example.com/something/1234/.
However, this is a good example of solving a problem that creates other problems. Patrick Hofman's and Jeow Li Huan's comments are correct — you have your canonicity issue figured out but now you have to deal with example.com and www.example.com generating their own set of cookies etc. As such, pick one scheme and stick to it by doing a permanent URL redirection (HTTP 301) on URLs matching the other scheme. You will then be able to use your original code:
<link rel="canonical" href="#Url.Action("Index", Html.GetTitleType(Model.TitleType), new { i = Model.Title.Title_Id }, Request.Url.Scheme)" />
...with no issues, as Request.Url.Scheme will always be the same due to the HTTP 301 you enforced on the other scheme.
Select your site in IIS manager then click on binding, add a binding with the host name example.com (without www).
I've got some (badly written) legacy code that I have to modify but I'm having an odd problem with the prefixing of the controls.
The main page has several include files, including cpct_cost.aspx.
Within that included page is a control EquipmentCost:
<INPUT id="EquipmentCost" type="text" name="EquipmentCost" runat="server" size="10" onchange="TotalCost();" class="bk">
Another page references that control in client side javascript:
function TotalCost()
{
var a = document.CPCT_FORM.cpct_cost_EquipmentCost.value;
This is throwing a client error because when I run the code locally, the control is being named with a $ instead of an _:
<input name="cpct_cost$EquipmentCost" type="text" id="cpct_cost_EquipmentCost" size="10" onchange="TotalCost();" class="bk" />
And as a result, the client side javascript can't find the element in question.
The legacy code on the server handles this differently - the control name there is processed as:
<input name="cpct_cost:EquipmentCost" id="cpct_cost_EquipmentCost" type="text" size="10" onchange="TotalCost();" class="bk" />
and this is being processed correctly.
I thought at first it might be a local IIS setting, so I compiled my code and deployed it to the dev server, but the behavior was identical to my local execution.
I'm using what are supposed to be the latest source files, I haven't changed any project settings, so ... is there some way I can force the code from my machine to use the : instead of $? Or ... what am I missing?
The project is currently on the proposal list to be completely rearchitected, (so please, no suggestions to redesign the app ;) ) but in the mean time, I have a short term requirement to implement some minor new functionality in this ugly old beast, and I've got to get it done ASAP. What's frustrating is - I haven't changed these parts of the code at all, but the behavior is changing anyway.
UPDATE
Apparently the naming prefix used in at least .NET 1.1 is somewhat random, because after several builds, while I was trying various ways to work around this, the controls ended up getting the right name. So now I'm just not changing the code, which sucks because I really hate taking this "freeze it while it's randomly right" approach.
You could pass in a reference to the input control as a parameter to the JS function, ie:
<INPUT id="EquipmentCost" type="text" name="EquipmentCost" runat="server" size="10" onchange="TotalCost(this);" class="bk">
function TotalCost(txtEquipCost) {
var a = txtEquipCost.value;
}
Then it doesn't matter what the id is.
EDIT:
If you have more controls, create JS variables on the page, eg:
var txtEquipCost = document.getElementById('<%= YourControl.ClientID %>');
var txtOtherCost = document.getElementById('<%= YourOtherControl.ClientID %>');
Then the onChange function call could be TotalCost(txtEquipCost, txtOtherCost)
EDIT2:
See this question about ClientId and UniqueId which may be useful:
C# asp.net Why is there a difference between ClientID and UniqueID?
You could change your Javascript to use the id that is getting generated.
function TotalCost()
{
var a = document.getElementById('<%= YourControl.ClientID %>').value;
}
Also if you need absolute control over the generated id of that control it turns out that in asp.net 4.0 the ClientIDMode property was introduced so that developers have more control over how that id is generated.
Check out these two sources
http://msdn.microsoft.com/en-us/library/system.web.ui.control.clientid.aspx
http://weblogs.asp.net/asptest/archive/2009/01/06/asp-net-4-0-clientid-overview.aspx