I am having a cookie problem in the below example. the cookie does get created and when i put a debug point after its creation i can check whats in the cookie with a watch. however, when i restart the website, the cookie is still there, but has become empty and will not create the model (all fields empty are null.)
I looked around and found bugs relating to using response.Cookie and having no expiry date, but i changed things around and it stays empty. Am i doing something wrong or is this because im using localhost?
[HttpGet]
[Autorize]
public ActionResult ManagePaymentRun()
{
ViewData["currentAction"] = "Index";
payments.AccountNo = Request.Cookies["FSCSPayments"]["AccountNo"];
payments.SortCode = Request.Cookies["FSCSPayments"]["SortCode"];
payments.FirstChequeNo = "2";// Request.Cookies["FSCSPayments"]["FirstChequeNo"];
payments.FileName = Request.Cookies["FSCSPayments"]["FileName"];
payments.FRN = Request.Cookies["FSCSPayments"]["FRN"];
payments.JobNumber = Request.Cookies["FSCSPayments"]["JobNumber"];
payments.StartRecNo = Request.Cookies["FSCSPayments"]["StartRecNo"];
return View(payments);
}
internal void CreateCookie()
{
HttpCookie cookie = new HttpCookie("FSCSPayments");
cookie.Values.Add("AccountNo", payments.AccountNo);
cookie.Values.Add("SortCode", payments.SortCode);
cookie.Values.Add("FirstChequeNo", payments.FirstChequeNo);
cookie.Values.Add("FileName", payments.FileName);
cookie.Values.Add("FRN", payments.FRN);
cookie.Values.Add("JobNumber", payments.JobNumber);
cookie.Values.Add("StartRecNo", payments.StartRecNo);
cookie.Expires = DateTime.Now.AddDays(14);
cookie.Path = "/";
Request.Cookies.Add(cookie);
}
cookie.Path = "C:\\Documents and Settings\\Andy\\Cookies";
This is not intended to do what you think it does. You cannot specify where the cookie will be stored on the client computer. That's absolutely browser dependent and you have no control over it. It is to restrict the access of this cookie to certain parts of your site. So if you don't want restriction simply set it to cookie.Path = "/".
Also your ManagePaymentRun action method looks strange. Why testing whether the user is authenticated when there's the [Autorize] attribute:
[HttpGet]
[Authorize]
public ActionResult ManagePaymentRun()
{
ViewData["currentAction"] = "Index";
var payments = new Payments();
payments.AccountNo = Request.Cookies["FSCSPayments"]["AccountNo"];
payments.SortCode = Request.Cookies["FSCSPayments"]["SortCode"];
payments.FirstChequeNo = "2";// Request.Cookies["FSCSPayments"]["FirstChequeNo"];
payments.FileName = Request.Cookies["FSCSPayments"]["FileName"];
payments.FRN = Request.Cookies["FSCSPayments"]["FRN"];
payments.JobNumber = Request.Cookies["FSCSPayments"]["JobNumber"];
payments.StartRecNo = Request.Cookies["FSCSPayments"]["StartRecNo"];
return View(payments);
}
I think you should trobleshoot the problem, I have 3 suggestions:
1) cookie.Expires = DateTime.Now.AddDays (14);
2) be careful with the .Add(Key, Value), Values should be safe not contain some symbols, althoug i think an exception is raised
3) specify the cookie.path
but my bet is the first one.
This problem is solved and was due to the fact that i used IIS 5 and MVC. we copied this project over to a IIS7 pc now and we got the cookies working.
Related
Hi I needed a serious help
i have tried everything but am not able to change the path of ASP.NET_sessionid cookie
its path is always set to "/" , i want to set it to a folder or directory
this issue need to be solved as it was raised by app security team
have tried , iis rewrite rule , custom session id manager
any help much aprreciated
As #iamdln said, you need to create your own SessionIDManager but you also need to config it on your Web.config.
It worked for me.
Your SessionIdManager class,
public class MySessionIDManager : SessionIDManager, ISessionIDManager
{
void ISessionIDManager.SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
{
base.SaveSessionID(context, id, out redirected, out cookieAdded);
if (cookieAdded)
{
var name = "ASP.NET_SessionId";
var cookie = context.Response.Cookies[name];
cookie.Path = "/yourPath";
}
}
}
Web.config, replace namespace and class for yours.
This goes inside <system.web> section.
<sessionState sessionIDManagerType = "Namespace.MySessionIDManager"></sessionState>
Original links:
ASP.NET Forum - Explains how to override path
StackOverFlow - Explains how to override domain
Both are quite similar anyway.
You will need to create your own SessionIDManager which is inherited from ISessionIDManager and change the cookie.Path to whatever you want.
static HttpCookie CreateSessionCookie(String id) {
HttpCookie cookie;
cookie = new HttpCookie(Config.CookieName, id);
cookie.Path = "/";
cookie.SameSite = Config.CookieSameSite;
// VSWhidbey 414687 Use HttpOnly to prevent client side script manipulation of cookie
cookie.HttpOnly = true;
return cookie;
}
I have following code in my Home-controller:
public ActionResult MyPage()
{
if (HttpContext.Request.Cookies["User"] == null)
{
//Create cookie
return RedirectToAction("MyPage", "Home");
}
else
{
string User = HttpContext.Request.Cookies["User"].Value;
foreach (var user in Data.MyUsers)
{
if (user.username == User)
{
//Do some stuff
return View("MyPage");
}
}
HttpContext.Request.Cookies.Remove("User");
//HttpContext.Response.Cookies.Remove("User"); works not sorry ;(
return RedirectToAction("MyPage", "Home");
}
}
Problem: The application don’t delete the cookie (why ever) and run in a loop because the application doesn’t find the user in the data. (The problem is not that the application doesn’t find the user, the problem is the cookie-issue)
Question: How I can fix this issue because in another project of me I works fine. I copy and pasted the code from my other project in my new project, but in the new project it will not work. Yes I use the same version of the asp.net framework :)
Hope you can help me… I’m at the end of my knowhow about c#....
Thank you very much.
Use Expire Property, and set negative value to it, this will expires the cookie i.e in your word this will removed from cookies list.
String cookieName = Request.Cookies["User"].Name;
HttpCookie userCookie = new HttpCookie(cookieName);
userCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(userCookie);
You cant delete a cookie on client, but you can do expire
https://msdn.microsoft.com/en-us/library/ms178195.aspx
If you start a new Web Project, and create a new MVC4 application (with sub-kind as "WebApi", you can paste the below code in (overwriting HomeController.cs) to get the code to work.
I have a MVC4 application (with WebApi).
I am trying to set a custom-header in a MVC controller method and then do a RedirectToAction. The custom-header is not seen in the second mvc-controller-method.
I am able to set a cookie in the first mvc-controller-method and see it in the second mvc-controller-method (after a RedirectToAction).
Is there a way to see the custom-header I set in the second mvc-controller-method after a RedirectToAction ?
Thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
namespace MyMvc4WebApiProjectNamespace.Controllers
{
public class HomeController : Controller
{
private const string CustomCookieName = "CustomCookieName";
private const string CustomHeaderName = "X-CustomHeaderName";
private const string IISExpressRootUrl = "http://localhost:55937/"; /* open up the project properties and go to the web tab and find the iis-express area to get the correct value for your environment */
public ActionResult Index()
{
IEnumerable<string> webApiValues = null;
string value1 = null;
string value2 = null;
HttpClientHandler handler = new HttpClientHandler
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
using (var client = new HttpClient(handler))
{
string valuesUri = IISExpressRootUrl + "api/Values";
webApiValues = client
.GetAsync(valuesUri)
.Result
.Content.ReadAsAsync<IEnumerable<string>>().Result;
if (null != webApiValues)
{
value1 = webApiValues.ElementAt(0);
value2 = webApiValues.ElementAt(1);
}
else
{
throw new ArgumentOutOfRangeException("WebApi call failed");
}
}
HttpCookie customCookie = new HttpCookie(CustomCookieName, "CustomCookieValue_ThisShowsUpIn_MyHomeControllerAlternateActionResult_Method");
Response.Cookies.Add(customCookie);
HttpContext.Response.AppendHeader(CustomHeaderName, "CustomHeaderValue_This_Does_Not_Show_Up_In_MyHomeControllerAlternateActionResult_Method");
//Response.AppendHeader(CustomHeaderName, value2);
return RedirectToAction("MyHomeControllerAlternateActionResult");
}
public ActionResult MyHomeControllerAlternateActionResult()
{
IEnumerable<string> webApiReturnValues = null;
CookieContainer cookieContainer = new CookieContainer();
foreach (string cookiename in Request.Cookies)
{
if (cookiename.Equals(CustomCookieName, StringComparison.OrdinalIgnoreCase))
{
var cookie = Request.Cookies[cookiename];
cookieContainer.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, "localhost"));
}
}
if (cookieContainer.Count < 1)
{
throw new ArgumentOutOfRangeException("CookieContainer did not find the cookie I was looking for");
}
else
{
Console.WriteLine("This is what actually happens. It finds the cookie.");
}
HttpClientHandler handler = new HttpClientHandler
{
UseCookies = true,
UseDefaultCredentials = true,
PreAuthenticate = true,
CookieContainer = cookieContainer
};
using (var client = new HttpClient(handler))
{
bool customHeaderWasFound = false;
if (null != this.Request.Headers)
{
if (null != this.Request.Headers[CustomHeaderName])
{
IEnumerable<string> headerValues = this.Request.Headers.GetValues(CustomHeaderName);
client.DefaultRequestHeaders.Add(CustomHeaderName, headerValues);
customHeaderWasFound = true;
}
}
/*I wouldn't expect it to be in the below, but I looked for it just in case */
if (null != this.Response.Headers)//
{
if (null != this.Response.Headers[CustomHeaderName])
{
IEnumerable<string> headerValues = this.Response.Headers.GetValues(CustomHeaderName);
client.DefaultRequestHeaders.Add(CustomHeaderName, headerValues);
customHeaderWasFound = true;
}
}
if (!customHeaderWasFound)
{
Console.WriteLine("This is what actually happens. No custom-header found. :( ");
}
string valuesUri = IISExpressRootUrl + "api/Values";
webApiReturnValues = client
.GetAsync(valuesUri)
.Result
.Content.ReadAsAsync<IEnumerable<string>>().Result;
if (null == webApiReturnValues)
{
throw new ArgumentOutOfRangeException("WebApi call failed");
}
}
return View(); /* this will throw a "The view 'MyHomeControllerAlternateActionResult' or its master was not found or no view engine supports the searched locations" error, but that's not the point of this demo. */
}
}
}
Response headers are never copied automatically to requests - so setting any custom headers on response will not impact next request issued to handle 302 redirect.
Note that it is the case even with cookies: response comes with "set this cookie" header, and all subsequent request will get "current cookies" header.
If you have your own client you may be able to handle 302 manually (not possible if you are using browser as client).
As another answer stated, response headers are about this response, not the next one. Redirecting is not a server-side action. A redirect instructs the client to perform a completely new request, and of course in a new request, the response headers for the old request are not present. So return RedirectToAction("MyHomeControllerAlternateActionResult"); is guaranteed to not have this response's headers when the browser initiates the new request.
In trying to solve this problem, one might think of trying to persist the data to the next request server-side, such as through a cookie or in an explicit session variable, or implicitly via use of ViewBag/ViewData/TempData. However, I don't recommend this as using session state heavily has performance implications in large/high-usage web sites, plus there are other negative and subtle side-effects that you may run into down the road. For example, if a person has two browser windows open to the same web site, they can't be doing different actions reliably, as the session data for one window can end up being served to the other one. Avoid session usage as much as possible in your web site design—I promise this will benefit you down the road.
A slightly better way, though still with its problems, is to redirect to a URL with querystring parameters containing a payload. And, instead of the whole set of data, you can provide a key that can be pulled from the session (as long as it's also bound to their IP address and is large like a GUID or two together). However, relying on session state is still not ideal as stated before.
Instead, consider using server-side redirection such as child actions. If you find that hard because what you want to call is a main controller you have a few options:
If you're using dependency injection, add a parameter to the current controller (saving it from the constructor and using it in the request method) that is the desired controller you want to "redirect" to. You can then call that controller directly. This may not be ideal (as all calls to this controller also have to new up a copy of that one), but it does work. Trying to new up the other controller manually can also work, but for reasons I don't fully remember, I think this can give some additional problems. In any case, this method can give issues accessing the HttpRequest context and other context objects correctly, though this can be worked around.
Rearchitect your application so that controllers are not the place where full pages are rendered. Instead, use them as "smart routers" that call child actions to perform the real work. Then, you can call the same child actions from any controller. But this still has problems.
Perhaps the best way is to add custom routing logic through action filters or other means (search the web!) so that the correct controller is hit in the first place! This may not always be possible, but sometimes the need to redirect to another controller mid-procedure actually points to a larger design problem. Focusing on how to cause the knowledge of which controller to hit to be available earlier in the pipeline (such as during routing) can reveal architecture problems, and can reveal likely solutions to them.
There may be other options that I haven't thought of, but at least you have a few alternatives to the simple "no way to do that."
I was able to do something similar like what the user is requesting in the following (rudimentary) way:
In the redirect, add a custom query string parameter
Create a custom Module that checks for that parameter and appends the custom header (read http://dotnetlionet.blogspot.com/2015/06/how-to-add-httpmodule-in-mvc5.html on how to do your own module)
In this way I was able to get my custom headers to be picked up
I am using Fortify to scan my code. It is identifying the error "Header Manipulation: Cookies". Further it says "includes unvalidated data in an HTTP cookie". My code is below.
String cookieName = "Foo";
System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex("[^a-zA-Z0-9 -]");
String FullCookieName = ".OmniPro" + cookieName;
FullCookieName = rgx.Replace(FullCookieName, "");
HttpCookie oldCookie = Request.Cookies[FullCookieName] ;
if ( oldCookie != null )
{
oldCookie.Expires = DateTime.Now.AddDays( -1 );
Response.Cookies.Add( oldCookie );
}
The error is identified on "Cookies.Add".
My intention is to just expire the old cookie. I have found no way to make Fortify happy. Any help would be appreciated.
The problem is taking the old cookie and then sending it back out. Cookies are not considered a trusted input for Fortify because they can be edited by the user. You would want to validate what is inside the cookie before adding it to the response. Even when you do this, Fortify will still likely report the issue. When doing input validation Fortify doesn't trust your validation inherently. You have to create a custom rule to do that. Once you think the input is sufficiently sanitized you could also just suppress the issue.
Fortify has a user community at https://protect724.hp.com that is also monitored by support. You may get quicker answers there.
I changed the code to be like below and Fortify accepted it.
String cookieName = "Foo"
System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex("[^a-zA-Z0-9 -]");
String FullCookieName = ".OmniPro" + cookieName;
HttpCookie oldCookie = Request.Cookies[FullCookieName];
if (oldCookie != null)
{
String DeleteCookieName = rgx.Replace(FullCookieName, "");
HttpCookie expiredCookie = new HttpCookie(DeleteCookieName) { Expires = DateTime.Now.AddDays(-1) };
HttpContext.Current.Response.Cookies.Add(expiredCookie); // overwrite it
}
Thanks
It seems to me that the extension .OmniPro has a very specific use case, which I don't question. However, the regular expression doesn't seem to be essential.
Much simpler code passes the HP's Fortify scan for header manipulation prevention:
HttpCookie expiredCookie = new HttpCookie(DeleteCookieName)
{ Expires = DateTime.Now.AddDays(-1) };
HttpContext.Current.Response.Cookies.Add(expiredCookie); // Overwrite cookie.
Moreover, for these kind of cookies which expire immediately (see DateTime.Now.AddDays(-1)) I'm a bit sceptical if it's not a false positive, because this cookie can be never fetched - it simply expires before it has been created.
I have an application that leverages a cookie to support a quasi-wizard (i.e. it's a set of pages that are navigated to by each other, and they must occur in a specific order, for registration).
When the Logon.aspx page is loaded - the default page - the browsers cookies look right.
There's one cookie and it has the right value. This ensures that the next page, which is an enrollment agreement, knows that it was loaded from the Logon.aspx page. However, when I get to that page the browsers cookies look much different:
Now we have two of the same cookie.
This doesn't appear to be causing any real issues - but I can't be sure it won't. So, let me show you the code I'm using to set the cookie (because maybe there's something wrong with it):
if (!this.IsPostBack)
{
Utility.HandleReferrer(Request, Response, "Logon.aspx");
Response.Cookies["lastpage"].Value = "Enroll.aspx";
}
and the HandleReferrer method looks like this:
static public void HandleReferrer(HttpRequest request, HttpResponse response, string expectedReferrer)
{
var cookie = request.Cookies["lastpage"];
if (cookie != null && cookie.Value.ToLower().Contains(expectedReferrer.ToLower()))
{
return;
}
response.Redirect("Logon.aspx");
}
So, why in the world does it duplicate this cookie? It doesn't ever seem to create more than two.
I suggest you do one of the following.
First, get the latest glimpse and try again.
If it is still showing 2 cookies with that name then get firebug and/or fiddler and look at it that way. If I had to take a guess I'd say there's either something wrong in glimpse or something wrong in how you are interpreting the results. Perhaps glimpse is showing what cookies existed before and then after the request was processed?
A third option is to simply emit the cookies collection from your own .net code. Something like:
foreach(HttpCookie cookie in request.Cookies) {
Response.Write(String.Format("{0} = {1}", cookie.Name, cookie.Value));
}
and see what happens.
I tried another approach, by creating a method that will return the latest cookie occurrence, this way I'll always get the right data.
This method expect the collection of cookies from Request, and the name of the searched cookie, and returns the latest ticket (the information that is normally encrypted)
private static FormsAuthenticationTicket GetLatestCookie(HttpCookieCollection cookies, string cookieName) {
var cookieOccurrences = new List<FormsAuthenticationTicket>();
for (int index = 0; index < cookies.Count; index++) {
if (cookies.GetKey(index) == cookieName) {
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookies[index].Value);
cookieOccurrences.Add(ticket);
}
}
DateTime oldestTime = DateTime.MinValue;
FormsAuthenticationTicket oldestTicket = null;
foreach (var formsAuthenticationTicket in cookieOccurrences) {
if (formsAuthenticationTicket.Expiration > oldestTime) {
oldestTime = formsAuthenticationTicket.Expiration;
oldestTicket = formsAuthenticationTicket;
}
}
return oldestTicket;
}