Zugriffskontrolle-Zulassungsursprung mit mehreren Domänen

97

In meiner web.config möchte ich mehr als eine Domain für die access-control-allow-originDirektive angeben . Ich möchte nicht verwenden *. Ich habe diese Syntax ausprobiert:

<add name="Access-Control-Allow-Origin" value="http://localhost:1506, http://localhost:1502" />

dieses

<add name="Access-Control-Allow-Origin" value="http://localhost:1506 http://localhost:1502" />

dieses

<add name="Access-Control-Allow-Origin" value="http://localhost:1506; http://localhost:1502" />

und das hier

<add name="Access-Control-Allow-Origin" value="http://localhost:1506" />
<add name="Access-Control-Allow-Origin" value="http://localhost:1502" />

aber keiner von ihnen funktioniert. Was ist die richtige Syntax?

Sam
quelle

Antworten:

77

Es kann nur einen Access-Control-Allow-OriginAntwortheader geben, und dieser Header kann nur einen Ursprungswert haben. Damit dies funktioniert, benötigen Sie daher folgenden Code:

  1. Nimmt den OriginAnforderungsheader.
  2. Überprüft, ob der Ursprungswert einer der Whitelist-Werte ist.
  3. Wenn es gültig ist, setzt der Access-Control-Allow-OriginHeader diesen Wert.

Ich glaube nicht, dass es eine Möglichkeit gibt, dies ausschließlich über die web.config zu tun.

if (ValidateRequest()) {
    Response.Headers.Remove("Access-Control-Allow-Origin");
    Response.AddHeader("Access-Control-Allow-Origin", Request.UrlReferrer.GetLeftPart(UriPartial.Authority));

    Response.Headers.Remove("Access-Control-Allow-Credentials");
    Response.AddHeader("Access-Control-Allow-Credentials", "true");

    Response.Headers.Remove("Access-Control-Allow-Methods");
    Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
}
Monsur
quelle
2
Das beantwortet meine Frage. Ich bin nicht sicher, warum Microsoft nicht zulässt, mehrere Ursprünge in der web.config anzugeben ....
Sam
17
Wo kann ich diesen Code hinzufügen? Ich habe Klartextdateien, die vom Server generiert und über AJAX gelesen wurden, überhaupt keinen Code. Wo kann ich den Code ablegen, um den Zugriff auf Textdateien in meinem Verzeichnis einzuschränken?
Harry
3
@Simon_Weaver Es gibt einen *Wert, mit dem jeder Ursprung auf die Ressource zugreifen kann. Die ursprüngliche Frage bezog sich jedoch auf die Whitelist einer Reihe von Domains.
Monsur
2
Da ich neu bei asp .net bin, kann ich fragen, wo ich diesen Code in mein asp .net Web-API-Projekt einfügen kann.
Amrit
91

Für IIS 7.5+ und Rewrite 2.0 können Sie Folgendes verwenden:

<system.webServer>
   <httpProtocol>
     <customHeaders>
         <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
         <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
     </customHeaders>
   </httpProtocol>
        <rewrite>            
            <outboundRules>
                <clear />                
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?domain1\.com|(.+\.)?domain2\.com|(.+\.)?domain3\.com))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>           
            </outboundRules>
        </rewrite>
 </system.webServer>

Erläutern des RESPONSE_Access_Control_Allow_OriginTeils der Servervariablen :
In Rewrite können Sie eine beliebige Zeichenfolge verwenden, RESPONSE_und es wird der Antwortheader erstellt, wobei der Rest des Wortes als Headername verwendet wird (in diesem Fall Access-Control-Allow-Origin). Beim Umschreiben werden die Unterstriche "_" anstelle der Bindestriche "-" verwendet (beim Umschreiben werden sie in Bindestriche umgewandelt).

Erläutern der Servervariablen HTTP_ORIGIN:
Ebenso können Sie in Rewrite einen beliebigen Anforderungsheader HTTP_als Präfix verwenden. Gleiche Regeln für die Bindestriche (verwenden Sie die Unterstriche "_" anstelle der Bindestriche "-").

Paco Zarate
quelle
Können Sie sich Gründe vorstellen, warum dies mit IIS 7.5 nicht funktioniert?
Phil Ricketts
Ich denke es sollte funktionieren. Ich habe die IIS 8.5-Version angegeben, weil ich sie dort getestet habe.
Paco Zarate
4
@ PacoZarate Schön, toller Tipp. Um die Regex zu vereinfachen und allgemeiner zu gestalten, können Sie - verwenden (http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net))). Auf diese Weise können Sie ganz einfach andere Domänen hinzufügen und mehrere Top-Level-Domänen (z. B. com, org, net usw.) unterstützen.
Merlin
4
Ich habe es gerade in IIS 7.5 versucht. Scheint gut zu funktionieren.
Prescient
2
Probleme beim Zwischenspeichern? Nachdem ich die web.config optimiert habe, stimmt die erste Website, zu der ich gehe, gut überein, aber die zweite gibt den gleichen Header wie die erste zurück. Dadurch stimmen die Domains nicht zu gut überein.
Airn5475
20

In Web.API kann dieses Attribut Microsoft.AspNet.WebApi.Corswie unter http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api beschrieben hinzugefügt werden

In MVC können Sie ein Filterattribut erstellen, um diese Arbeit für Sie zu erledigen:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = true, Inherited = true)]
public class EnableCorsAttribute : FilterAttribute, IActionFilter {
    private const string IncomingOriginHeader = "Origin";
    private const string OutgoingOriginHeader = "Access-Control-Allow-Origin";
    private const string OutgoingMethodsHeader = "Access-Control-Allow-Methods";
    private const string OutgoingAgeHeader = "Access-Control-Max-Age";

    public void OnActionExecuted(ActionExecutedContext filterContext) {
        // Do nothing
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var isLocal = filterContext.HttpContext.Request.IsLocal;
        var originHeader = 
             filterContext.HttpContext.Request.Headers.Get(IncomingOriginHeader);
        var response = filterContext.HttpContext.Response;

        if (!String.IsNullOrWhiteSpace(originHeader) &&
            (isLocal || IsAllowedOrigin(originHeader))) {
            response.AddHeader(OutgoingOriginHeader, originHeader);
            response.AddHeader(OutgoingMethodsHeader, "GET,POST,OPTIONS");
            response.AddHeader(OutgoingAgeHeader, "3600");
        }
    }

    protected bool IsAllowedOrigin(string origin) {
        // ** replace with your own logic to check the origin header
        return true;
    }
}

Aktivieren Sie es dann entweder für bestimmte Aktionen / Controller:

[EnableCors]
public class SecurityController : Controller {
    // *snip*
    [EnableCors]
    public ActionResult SignIn(Guid key, string email, string password) {

Oder fügen Sie es für alle Controller in Global.asax.cs hinzu

protected void Application_Start() {
    // *Snip* any existing code

    // Register global filter
    GlobalFilters.Filters.Add(new EnableCorsAttribute());
    RegisterGlobalFilters(GlobalFilters.Filters);

    // *snip* existing code
}
Rob Church
quelle
Wissen Sie, für welche Versionen von .Net / MVC dies funktioniert?
Keab42
Ich verwende dies erfolgreich in .net 4 / MVC 3 - soweit mir bekannt ist, sollte es in höheren Versionen funktionieren, aber es gibt möglicherweise eine bevorzugte Methode zum Registrieren des globalen Filters in späteren MVC-Versionen.
Rob Church
Bitte beachten Sie nur die WEB API 2-Lösung. nicht für WEB API 1.
Samih A
5

Nachdem ich jede Antwort gelesen und ausprobiert hatte, half mir keiner von ihnen. Bei der Suche an anderer Stelle habe ich festgestellt, dass Sie ein benutzerdefiniertes Attribut erstellen können, das Sie dann Ihrem Controller hinzufügen können. Es überschreibt die EnableCors und fügt die Whitelist-Domänen hinzu.

Diese Lösung funktioniert gut, da Sie die Whitelist-Domänen in der Webkonfiguration (Appsettings) haben können, anstatt sie im EnableCors-Attribut auf Ihrem Controller zu harcodieren.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsByAppSettingAttribute : Attribute, ICorsPolicyProvider
{
    const string defaultKey = "whiteListDomainCors";
    private readonly string rawOrigins;
    private CorsPolicy corsPolicy;

    /// <summary>
    /// By default uses "cors:AllowedOrigins" AppSetting key
    /// </summary>
    public EnableCorsByAppSettingAttribute()
        : this(defaultKey) // Use default AppSetting key
    {
    }

    /// <summary>
    /// Enables Cross Origin
    /// </summary>
    /// <param name="appSettingKey">AppSetting key that defines valid origins</param>
    public EnableCorsByAppSettingAttribute(string appSettingKey)
    {
        // Collect comma separated origins
        this.rawOrigins = AppSettings.whiteListDomainCors;
        this.BuildCorsPolicy();
    }

    /// <summary>
    /// Build Cors policy
    /// </summary>
    private void BuildCorsPolicy()
    {
        bool allowAnyHeader = String.IsNullOrEmpty(this.Headers) || this.Headers == "*";
        bool allowAnyMethod = String.IsNullOrEmpty(this.Methods) || this.Methods == "*";

        this.corsPolicy = new CorsPolicy
        {
            AllowAnyHeader = allowAnyHeader,
            AllowAnyMethod = allowAnyMethod,
        };

        // Add origins from app setting value
        this.corsPolicy.Origins.AddCommaSeperatedValues(this.rawOrigins);
        this.corsPolicy.Headers.AddCommaSeperatedValues(this.Headers);
        this.corsPolicy.Methods.AddCommaSeperatedValues(this.Methods);
    }

    public string Headers { get; set; }
    public string Methods { get; set; }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,
                                               CancellationToken cancellationToken)
    {
        return Task.FromResult(this.corsPolicy);
    }
}

    internal static class CollectionExtensions
{
    public static void AddCommaSeperatedValues(this ICollection<string> current, string raw)
    {
        if (current == null)
        {
            return;
        }

        var paths = new List<string>(AppSettings.whiteListDomainCors.Split(new char[] { ',' }));
        foreach (var value in paths)
        {
            current.Add(value);
        }
    }
}

Ich habe diesen Leitfaden online gefunden und er hat wie ein Zauber funktioniert:

http://jnye.co/Posts/2032/dynamic-cors-origins-from-appsettings-using-web-api-2-2-cross-origin-support

Ich dachte, ich würde das hier für jeden in Not fallen lassen.

Helpha
quelle
Dies ist eine reine Linkantwort. Bitte lassen Sie die Antwort stattdessen für sich stehen.
Stellen Sie Monica
1
Ok, ich bin neu hier, ist das eher so, wie es sein soll?
Helpha
3

Ich habe es geschafft, dies im Code für die Bearbeitung von Anfragen zu lösen, nachdem ich den Rat von 'Monsur' befolgt habe.

string origin = WebOperationContext.Current.IncomingRequest.Headers.Get("Origin");

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);
bsandhu
quelle
Dies ist beispielsweise in Webform der Fall. Verwenden Sie einfach Request.Headers, sofern verfügbar. Verwenden Sie bei Bedarf eine Whitelist, um nur zulässige Domains zu filtern.
Nach dem
3
Dies ist so gut wie das Hinzufügen von <add name = "Access-Control-Allow-Origin" value = "*" /> in der Datei
web.config
3

Für IIS 7.5+ können Sie das IIS CORS-Modul verwenden: https://www.iis.net/downloads/microsoft/iis-cors-module

Ihre web.config sollte ungefähr so ​​aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://localhost:1506">
                <allowMethods>                    
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
            <add origin="http://localhost:1502">
                <allowMethods>
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
        </cors>
    </system.webServer>
</configuration>

Die Konfigurationsreferenz finden Sie hier: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference

Mario Arturo
quelle
Wenn dies so funktioniert, wie es heißt, wünschte ich, Sie hätten dies vor 3 Jahren gepostet! Whoa!
Michael
1

Sie können diesen Code zu Ihrem asp.net-Webapi-Projekt hinzufügen

in der Datei Global.asax

    protected void Application_BeginRequest()
{
    string origin = Request.Headers.Get("Origin");
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
        Response.StatusCode = 200;
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
    }
}
Jackdon Wang
quelle
0

Sie können owin Middleware verwenden, um eine Cors-Richtlinie zu definieren, in der Sie mehrere Cors-Ursprünge definieren können

return new CorsOptions
        {
            PolicyProvider = new CorsPolicyProvider
            {
                PolicyResolver = context =>
                {
                    var policy = new CorsPolicy()
                    {
                        AllowAnyOrigin = false,
                        AllowAnyMethod = true,
                        AllowAnyHeader = true,
                        SupportsCredentials = true
                    };
                    policy.Origins.Add("http://foo.com");
                    policy.Origins.Add("http://bar.com");
                    return Task.FromResult(policy);
                }
            }
        };
Chayan Banerjee
quelle
-3

Du brauchst nur:

  • Fügen Sie Ihrem Projekt eine Global.asax hinzu.
  • <add name="Access-Control-Allow-Origin" value="*" />aus Ihrer web.config löschen .
  • Application_BeginRequestFügen Sie dies anschließend in die Methode von Global.asax ein:

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
    
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
        HttpContext.Current.Response.End();
    }

Ich hoffe diese Hilfe. diese Arbeit für mich.

joanrm20
quelle
Das Hinzufügen von "...- Origin: *" funktioniert nur, wenn Sie Anmeldeinformationen zulassen. Wenn Sie die zulässigen Anmeldeinformationen auf true gesetzt haben, müssen Sie eine Domäne angeben (nicht einfach *). Hier liegt der Kern dieses Problems. Andernfalls können Sie einfach "... allow-credentials: false" angeben und damit fertig sein.
Richard