In my project, there is a page that triggers a JSon script when a button is clicked. This script interacts with a web service. To ensure security, the code behind the page generates a script containing an object with a unique code. This code is then added to the header of the page. However, the web service fails to verify this code as it cannot find the specified header (in other words, the header does not exist).
The following code snippet generates the code and JavaScript object (in .cs file):
string cacheKey = User.Identity.Name + ":securityTicket";
string securityTicket = Guid.NewGuid().ToString();
Cache[cacheKey] = securityTicket;
string script = string.Format("SECURITY_TICKET = '{0}';", securityTicket);
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "securityKey", script, true);
This script adds the header (in .aspx file)
function onInvoke(sender, args) {
args.get_webRequest().get_headers()['securityTicket'] = SECURITY_TICKET;);
}
The backend code for the web service (asmx.cs or similar): HttpContext context = HttpContext.Current;
string headerTicket = context.Request.Headers["securityTicket"];
if (string.IsNullOrEmpty(headerTicket))
{
throw new SecurityException("Security ticket must be present.");
}
string cacheKey = context.User.Identity.Name + ":securityTicket";
string cacheTicket = (string)context.Cache[cacheKey];
if (string.Compare(headerTicket, cacheTicket, false) != 0)
{
throw new SecurityException("Security ticket mismatched.");
}
The issue arises when context.Request.Headers["securityTicket"] returns null.
Any insights or suggestions would be greatly appreciated. Thank you!
UPDATE:
The Web service:
namespace PV
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService()]
public class UserService : System.Web.Services.WebService
{
[WebMethod]
public bool ChangeUserPassword(object userID, object password)
{
EnsureTicket();
return PV.WebMethods.ChangeUserPassword(userID, password);
}
private void EnsureTicket()
{
HttpContext context = HttpContext.Current;
string headerTicket = context.Request.Headers["securityTicket"];
if (string.IsNullOrEmpty(headerTicket))
{
throw new SecurityException("Security ticket must be present.");
}
string cacheKey = context.User.Identity.Name + ":securityTicket";
string cacheTicket = (string)context.Cache[cacheKey];
if (string.Compare(headerTicket, cacheTicket, false) != 0)
{
throw new SecurityException("Security ticket mismatched.");
}
}
}
}
The Page:
<script type="text/javascript" language="javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(beginRequest);
function beginRequest(sender, args) {
prm._scrollPosition = null;
postbackElement = args.get_postBackElement();
}
var postbackElement;
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequest);
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(pageLoaded);
function pageLoaded() {
Sys.Net.WebRequestManager.add_invokingRequest(onInvoke);
if (typeof (postbackElement) === "undefined") {
return;
}
if ((postbackElement.id).indexOf("btnSelect") !== -1) {
$("html, body").animate({ scrollTop: "300px" });
}
}
function ApplicationLoadHandler() {
// InitScript is a custom function
// registered from the User Control
if (typeof InitScript == 'function')
InitScript();
}
if (Sys && Sys.Application) {
Sys.Application.add_load(ApplicationLoadHandler);
Sys.Application.notifyScriptLoaded();
}
function pageUnload() {
Sys.Net.WebRequestManager.remove_invokingRequest(onInvoke);
}
function onInvoke(sender, args) {
args.get_webRequest().get_headers()['securityTicket'] = SECURITY_TICKET;
alert('Security ticket: ' + args.get_webRequest().get_headers()['securityTicket']);
}
</script>
<%
Response.Write(@"
<script>
function ResetPassword()
{
var password = document.getElementById(""password"").value;
var id = document.getElementById(""ctl00_ctl00_ContentPlaceHolder1_cphContent_hdnUsrID"").value;
var d = {""userID"" : id, ""password"" : password };
$.ajax
({
type: ""POST"",
url: """ + "" + @"http://localhost:2297/wwwroot/Services/UserService.asmx/ChangeUserPassword"",
data: JSON.stringify(d),
contentType: ""application/json"",
dataType: ""json"",
success: function()
{
document.getElementById(""password"").value = '';
alert('Success');
$(""" + "#ctl00_ctl00_ContentPlaceHolder1_cphContent_pnlChangePassword" + @""").fadeOut();
$(""html, body"").animate
( {
scrollTop: $(""" + "#ctl00_ctl00_ContentPlaceHolder1_cphContent_pnlPerson" + @""").offset().top - 100
}, 1200);
},
error: function(msg)
{
if(msg === false)
{
alert('Error');
return;
}
}
})
}
function passwordChanged_Success() {
alert('Changed');
}
function passwordChanged_Failed() {
alert('Failed');
}
</script>"); %>
The page includes an update panel.
The page's code behind:
private void GenerateSecurityTicket()
{
string cacheKey = User.Identity.Name + ":securityTicket";
string securityTicket = Guid.NewGuid().ToString();
Cache[cacheKey] = securityTicket;
string script = string.Format("SECURITY_TICKET = '{0}';", securityTicket);
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "securityKey", script, true);
}
protected void Page_Load(object sender, EventArgs e)
{
this.GenerateSecurityTicket();
}