domenica 16 settembre 2018

Proteggere il codice sorgente in .net

In questo post trovate illustrata una procedura per aggiungere un po' di protezione ai vostri sorgenti c# relativi ad applicazioni windows forms, in certe condizioni l'applicazione rende inutili sia decompilatori che deoffuscatori e protegge il codice sorgente anche non offuscato,
qui il progetto https://sourceforge.net/projects/winformsprotector/




Uno scenario possibile : abbiamo un eseguibile da far testare da altri ma non vogliamo cederlo per il momento, possiamo quindi crittografare l' eseguibile ed andare sulla macchina di prova con il nostro exe crittografato ed il software per decrittografarlo ,inserire la password per decrittografarlo e caricarlo in memoria ,ci si potrebbe limitare a caricare l'exe in memoria e poi cancellare il file ma per fare questo dovremmo copiare sulla macchina di test l'eseguible in chiaro e questo comporterebbe la possibilità di appropriarsi del programma.

Per appropriarsi del codice di un eseguibile .net si possono usare dei software quali ILSpy che permettono di ottenere il codice sorgente , per proteggere il codice esistono dei software detti obfuscator che “offuscano” il codice ad esempio ConfuserEx(https://yck1509.github.io/ConfuserEx/ ) , esistono però anche dei deoffuscatori quali De4dot che permettono di risalire al codice pre-  offuscato. La battaglia tra offuscatori e deoffuscatori dura da anni .Per aggiungere sicurezza al proprio software,difendendolo dalla decompilazione si può fare anche qualcosa di diverso.In sostanza si può partire dall'eseguibile offuscato e farlo caricare da un altro eseguibile ,che chiamiamo “lanciatore”, in memoria.Con il software lanciatore ,o con altro software da noi preparato,crittografiamo il file offuscato usando una password da noi scelta .
Quando siamo sulla macchina dove andrà testato il file offuscato inseriamo la password ,carichiamo il file in memoria e qui lo decrittografiamo e lo eseguiamo,in pratica carichiamo l'Assembly in questo modo :

Assembly assembly1 = Assembly.Load(exe);
dove exe è l'array di bytes che compone l'eseguibile
in questo modo sulla macchina non esiste il file che intendiamo proteggere in chiaro ma esiste solo crittografato oppure in memoria ,

nel file eseguibile che s' intende proteggere(l'exe chiamato) bisogna modificare il main in questo modo:
in pratica aggiungete un metodo Start() che chiama il primo Form della vostra applicazione

namespace Ethical_Hacking
{
    static class Program
   {
     [STAThread]
     static void Main()
    {
       Application.EnableVisualStyles();
       Application.SetCompatibleTextRenderingDefault(false);
     Start();
    }

//il metodo seguente permette di superare gli eventuali problemi con il metodo SetCompatibleTextRenderingDefault
   public static void Start()
  {
   Form1 f = new Form1();
   f.ShowDialog();
   }

 }
}

nell'exe chiamante avremo quindi :
Assembly assembly1 = Assembly.Load(exe);
var programType1 = assembly1.GetTypes().FirstOrDefault(c => c.Name == "Program");
MethodInfo method1 = programType1.GetMethod("Start", BindingFlags.Public | BindingFlags.Static);
method1.Invoke(null, new object[] { });

ovvero viene invocato il metodo Start()

Se il file exe da proteggere usa dei package bisogna aggiungere questi package nel progetto (eseguibile) chiamante ,ad esempio se usiamo NewtonSoft.json nel programma da proteggere anche il programma chiamante deve avere NewtonSoft.Json nei suoi package

il punto debole di questa procedura è che un programma che registri lo schermo registrerebbe anche quando inseriamo la password,abbiamo quindi 2 possibilità :

           1) dobbiamo essere sicuri che sulla macchina su cui installiamo il software chiamante non ci siano simili programmi in esecuzione che registrano lo schermo(screen recorder) , il software chiamante usa una qwerty virtuale per cui siamo al riparo dalle possibili registrazioni dello stream della tastiera

OPPURE

    2) fornire una macchina di test sulla quale installare il software chiamante e caricare il software da proteggere quando  questa viene installata nella sua sede finale , ovvero potete provare il software che trovate su questa pagina

possiamo ovviamente impostare un “periodo” di prova per l'eseguibile scaduto il quale l'applicazione si chiude,il codice sorgente del progetto è sotto la licenza BSD.

Nel codice sorgente troverete due progetti zippati :WindowsFormsProtector e Ethical_Hacking ,
il primo è l'exe chiamante il secondo è l'exe chiamato (ovvero quello protetto) , qui il codice e l'installer : https://sourceforge.net/projects/winformsprotector/
Per qualsiasi problema,errore,suggerimento potete inviarmi un email oppure aggiungere un commento al post.L'eseguibile WindowsFormsProtector ha un help che permette di seguire uno per uno i passi necessari all'uso dell'applicazione






domenica 26 agosto 2018

Asp .Net MVC in pillole:routing,parteVIII


Routing: in MVC gli url non corrispondono ad un file fisico sul server ma corrispondono a metodi di classi che vengono invocati anche con parametri,le classi di cui parliamo sono i controllers ed i metodi sono le actions.

Il routing in asp .net mvc 5 si può fare oltre che nel modo classico attraverso il metodo RegisterRoutes della classe RouteConfig anche attraverso gli "attribute routes".
Per usare gli attributi di routing dobbiamo aggiungere la seguente riga al RouteConfig :

public static void RegisterRoutes(RouteCollection routes)
{
  ........
  routes.MapMvcAttributeRoutes();
  ........
}

supponiamo di considerare il controller home creato dal template di visual studio
public class HomeController : Controller
{
  public ActionResult Index()
  {
   return View();
  }
  [Route("aproposito")]
  public ActionResult About()
  {
   ViewBag.Message = "Your application description page.";
   return View();
  }
}

aggiungiamo un attributo di routing all'action About e digitiamo
otterremo la view about poichè viene eseguita l'action about ,per mantenere una coerenza a livello di controller si può aggiungere un RoutePrefix al controller:
[RoutePrefix("home")]
public class HomeController : Controller
{
//codice omesso per brevità
}
con questa modifica potremo chiamare l'action about in questo modo : "http://localhost:23745/home/aproposito" ,


possiamo avere più valori di routeattribute per la stessa action:
[Route("aproposito")]
[Route("riguardo")]
public ActionResult About()
{
  ViewBag.Message = "Your application description page.";
  return View();
}

possiamo chiamare l'action anche così: http://localhost:23745/home/riguardo
per evitare l'uso del prefix su un action da parte dell'engine di routing possiamo aggiungere una tilda come route:
sempre nella classe homecontroller :

[Route("~/")]
public ActionResult Contact()
{
  ViewBag.Message = "Your contact page.";
  return View();
}

proviamo a chiamare "http://localhost:23745/" ed otterremo la view contact.cshtml
possiamo aggiungere un elemento al path:

[Route("~/")]
[Route("~/ctc")]
public ActionResult Contact()
{
  ViewBag.Message = "Your contact page.";
  return View();
}

possiamo chiamare la seconda route, ed ottenere ancora la view contact.cshtml, anche in questo modo: "http://localhost:23745/ctc".
Possiamo aggiungere delle constraint per specificare il tipo di dato del parametro passato nell'url :
se ad esempio vogliamo che un parametro sia intero possiamo definire una route così:
[Route("testintautomobile/{id:int}")]
public ActionResult Details(int? id)
{
  if (id == null)
  {
   return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  Automobile automobile = db.Automobiles.Find(id);
  if (automobile == null)
  {
    return HttpNotFound();
  }
  return View(automobile);
}
se inseriamo la seguente url http://localhost:23745/testintautomobile/1 otterremo il dettaglio dell'auto con id "1"
se inseriamo http://localhost:23745/testintautomobile/babau otterremo un errore 404 ovvero impossibile trovare la risorsa
se togliamo la constraint "int" ovvero scriviamo una route così :
[Route("testintautomobile/{id}")]
public ActionResult Details(int? id)
{
  if (id == null)
  {
   return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  Automobile automobile = db.Automobiles.Find(id);
  if (automobile == null)
  {
   return HttpNotFound();
  }
  return View(automobile);
}

e chiamiamo http://localhost:23745/testintautomobile/sonounastringa, id nell'action sarà null e quindi il flusso cadrà nel primo if ed otterremo quest'errore:
"HTTP Error 400.0 - Bad Request
Richiesta errata"
Esistono constraint da utilizzare con l'attributo Route per i seguenti tipi : bool,datetime,decimal,double, float, guid,int ,long,string,regex,alpha(una stringa che contiene solo i caratteri A-Z e a-z)
Nel metodo RegisterRoutes , nel template di progetto, troviamo:

routes.MapRoute(
  name: "Default",
  url: "{controller}/{action}/{id}",
  defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);


se quindi non scegliamo un path successivo al numero di porta ovvero http://localhost:23745/ saremo indirizzati al controller "Home" e sarà chiamata l'action "Index" , così non sarà se ad esempio abbiamo anche aggiunto l'attributo [Route("~/")] all'action Contact
[Route("~/")]
public ActionResult Contact()
{
  ViewBag.Message = "Your contact page.";
  return View();
}
in questo caso se chiamiamo l'url http://localhost:23745/ ci verrà restituita la view contact.cshtml, è possibile definire un parametro opzionale con il "?" , ad esempio una route può essere [Route("automobile/{id?}")]

Dato che generalmente gli attributi Route sono più specifici è consigliabile registrare prima le route tramite attributi che le route "tradizionali" in quanto l'engine applica la prima route che matcha ovvero:
public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  routes.MapMvcAttributeRoutes();
  routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  );
}

nel codice soprastante la route "tradizionale" (chiamiamo così quella possibile prima dell'introduzione dell'attributo Route) ,è quella di nome "default" .
Le route tradizionali permettono una gestione centralizzata delle route ,l'uso degli attributi di routing permette di "associare" un action ad una route in modo specifico.
Il motore di routing ignora le request che fanno riferimento ad un file fisico sul disco,i file jpeg,css,javascript,etc.etc, vengono restituiti senza "passare" dal motore di routing .
Per evitare che il routing consideri determinati path si può usare un istanza della classe StopRoutingHandler() :

public static void RegisterRoutes(RouteCollection routes)
{
  routes.Add(new Route("{resource}.axd/{*pathInfo}", new StopRoutingHandler()));
  routes.MapMvcAttributeRoutes();
  routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  );
}
un altro modo per evitare che un path sia considerato dal motore di routing è il metodo IgnoreRoute:

public static void RegisterRoutes(RouteCollection routes)
{
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   routes.MapMvcAttributeRoutes();
   routes.MapRoute(
     name: "Default",
     url: "{controller}/{action}/{id}",
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  );
}
Quando si definisce una route si possono aggiungere delle constraints alle definizioni ,una di queste è l'HttpMethodConstraint che permette di decidere quale verbo http si deve usare per chiamare la route :

routes.MapRoute(
   name: "Default",
   url: "{controller}/{action}/{id}",
   defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
   constraints:new { httpMethod =new HttpMethodConstraint("GET") }
);


se vogliamo che l'id possa essere solo un intero possiamo ,in alternativa ad usare un attributo sull'action(id:int), aggiungere una constraints id = new IntRouteConstraint() ,per utilizzare le constraints dovete utilizzare il namespace System.Web.Mvc.Routing.Constraints; ,
potete usare più constraints:

constraints:new { httpMethod =new HttpMethodConstraint("PUT") ,
id = new IntRouteConstraint() }

E' possibile creare delle constraint custom utilizzando l'interfaccia IRouteConstraint implementando il metodo Match,
public class CustomConstraint : IRouteConstraint
{
public bool Match (HttpContextBase httpContext,Route route,string parameterName,
  RouteValueDictionary values,RouteDirection routeDirection)
  {
    return httpContext.Request.IsSecureConnection;
  }
}
ovvero la constraint custom è soddisfatta solo quando la chiamata è con protocollo Https.


giovedì 23 agosto 2018

Asp.Net mvc in pillole :sicurezza ,parteVII


Cross site scripting : si tratta di attacchi che iniettano codice lato client per attuare un attacco con il quale raccogliere,manipolare o reindirizzare informazioni riservate,nella maggioranza dei casi l'attacco può essere evitato encodando l'Html ,l'encoding html consiste nel rimpiazzare alcuni caratteri riservati in html con dei codici ,ne sono un esempio "<" e ">" , in MVC questo si può fare usando il metodo Html.Encode o Html.AttributeEncode .Usando il view engine Razor le stringhe vengono automaticamente encodate semplicemente con la "@" ,ad esempio :
@Model.LastName
è encodato automaticamente.
Anche gli HtmlHelpers encodano l'html prodotto.Per mettere in sicurezza la nostra applicazione dobbiamo sempre utilizzare anche Html.AttributeEncode per gli attributi e Url.Encode per le url.
Per quanto riguarda i valori dentro gli script javascript essi vanno encodati con Ajax.JavaScriptStringEncode.

Cross site request forgery:
questo tipo di attacco colpisce gli utenti autenticati di un sito,viene inserito del codice ad esempio in un tag src di un immagine che esegue un comando sull'applicazione web senza che l'utente lo voglia ,ad esempio:
<img src=''sitoA?azione=trasferire&quanto=1000&numerodiconto=1234567890" alt="fidati">
l'azione viene eseguita perchè l'utente è autenticato .
Per evitare questi attacchi è consigliabile non usare mai il verbo get per compiere azioni che modificano i dati.
Per evitare questi attacchi in MVC possiamo inoltre usare
@Html.AntiforgeryToken() dentro ogni form

<form action="/account/doaction" method="post" >
@Html.AntiforgeryToken()
....
....
</form>m
Html.AntiforgeryToken aggiunge ad ogni form  un campo hidden che contiene un valore unico ,questo valore è uguale al valore che viene salvato in un cookie di sessione nel browser dell'utente,l'action che viene chiamata (doaction) ha un attributo ValidateAntiForgeryToken che controlla i due valori.
Un modo per controllare se la request viene veramente dal nostro sito è scrivere un attributo custom che controlli se la proprietà HttpReferer contiene il valore corretto :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace WebApplication19
{
  public class HttpRefererValidationAttribute : AuthorizeAttribute
  {
   public HttpRefererValidationAttribute()
   {

   }
   public override void OnAuthorization(AuthorizationContext filterContext)
   {
    if (filterContext.HttpContext != null)
    {
     string hostName = "localhost";
     if (filterContext.HttpContext.Request.UrlReferrer == null)
     throw new System.Web.HttpException("manca il referer");
     if (filterContext.HttpContext.Request.UrlReferrer.Host != hostName)
     {
      throw new System.Web.HttpException("il form non appare inviato da questo sito");
     }
     else
     {
       //rimuovere questo ramo else per uso non di esempio
      filterContext.RequestContext.HttpContext.Response.Write("<center>il referer appare essere correttamente " + hostName + "</center>");
     }
   }
  }
 }
}

    aggiungiamo l'attributo al metodo Details:
    // GET: Automobiles/Details/5
[HttpRefererValidation]
public ActionResult Details(int? id)
  {
   if (id == null)
   {
     return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
   }
   Automobile automobile = db.Automobiles.Find(id);
   if (automobile == null)
   {
    return HttpNotFound();
   }
   return View(automobile);
}


eseguiamo il progetto con F5,mettiamo un break point sul metodo "OnAuthorization" e inseriamo come indirizzo nel browser "http://localhost:23745/Automobiles" ,viene quindi chiamato da mvc il metodo index del controller AutomobilesController ,scegliamo una macchina e selezioniamo Details
essendo l'host "localhost" che è il nome previsto otteniamo:
-Settare i cookies per evitare che siano utilizzati da script malevoli : per evitare che i cookies siano utilizzati dagli script è necessario che il loro attributo HttpOnly sia settato a true,questo si può fare a livello di singolo cookie prodotto dal sito:

Response.Cookies["TestCookie"].Value="value of TestCookie";
Response.Cookies["TestCookie"].HttpOnly=true;

oppure settato nel web.config :
<httpCookies httpOnlyCookies="true" requireSSL="false" domain="" />

-Open Redirection Attacks: si tratta di attacchi che portano la vittima
 a navigare su siti che sono in mano all'attaccante,creando un progetto
 mvc tramite template troviamo un controller di nome AccountController
 che contiene un metodo che impedisce inserendo un url verso un sito 
esterno che l'utente vi sia reindirizzato ,segue il metodo:

private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            return RedirectToAction("Index", "Home");
        }
il metodo controlla che l'url verso cui reindirizzare l'utente sia un url
 locale con il metodo IsLocalUrl,il metodo non traccia il tentativo 
ma volendo possiamo aggiungere un metodo, totalmente fatto da noi 
oppure utilizzare delle librerie ,per loggare il tentativo,

private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            } else
            {
                SaveThreat(returnUrl);
            }
            return RedirectToAction("Index", "Home");
        }

Proteggere il codice sorgente in .net

English In questo post trovate illustrata una procedura per aggiungere un po' di protezione ai vostri sorgenti c# relativi ad app...