Контроль доступу з дозволом на походження з кількома доменами


98

У своєму web.config я хотів би вказати більше одного домену для access-control-allow-originдирективи. Я не хочу використовувати *. Я спробував цей синтаксис:

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

ось цей

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

ось цей

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

і цей

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

але жоден з них не працює. Який правильний синтаксис?

Відповіді:


78

Access-Control-Allow-OriginЗаголовок відповіді може бути лише один , і цей заголовок може мати лише одне значення початку. Тому, щоб це працювало, вам потрібно мати якийсь код, який:

  1. Захоплює Originзаголовок запиту.
  2. Перевіряє, чи значення походження є одним із значень білого списку.
  3. Якщо він дійсний, встановлює Access-Control-Allow-Originзаголовок із цим значенням.

Я не думаю, що існує будь-який спосіб зробити це виключно через web.config.

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");
}

2
Це відповідає на моє запитання. Я не впевнений, чому корпорація Майкрософт забороняє вказувати кілька джерел у web.config ...
Сем,

17
Де я можу додати цей код? У мене є текстові файли, що генеруються сервером і читаються через AJAX, коду взагалі немає. Де я можу розмістити код, щоб обмежити доступ до текстових файлів у моєму каталозі?
Гаррі

3
@Simon_Weaver має *значення, яке дозволяє будь-якому джерелу отримати доступ до ресурсу. Однак оригінальне запитання стосувалося набору доменів у білий список.
monsur

2
оскільки я новачок у asp .net. чи можу я запитати, де я можу розмістити цей код у своєму веб-проекті asp .net?
Амріт

93

Для IIS 7.5+ і Rewrite 2.0 ви можете використовувати:

<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>

Пояснення RESPONSE_Access_Control_Allow_Originчастини змінної сервера :
У Rewrite ви можете використовувати будь-який рядок після, RESPONSE_і він створить заголовок відповіді, використовуючи решту слова в якості імені заголовка (у цьому випадку Access-Control-Allow-Origin). Перезапис використовує підкреслення "_" замість тире "-" (перезапис перетворює їх на тире)

Пояснення змінної сервера HTTP_ORIGIN:
Аналогічно, у Rewrite ви можете захопити будь-який заголовок запиту, використовуючи HTTP_як префікс. Ті самі правила з тире (використовуйте підкреслення "_" замість тире "-").


Чи можете ви придумати будь-які причини, чому це не спрацювало б з IIS 7.5?
Філ Рікеттс

Я думаю, це має спрацювати. Я вказав версію IIS 8.5, оскільки саме там я її тестував.
Пако Зарате

4
@PacoZarate Гарний, чудова порада. Щоб спростити регулярний вираз і зробити його загальнішим, ви можете використовувати - (http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net))). Таким чином ви можете додати інші домени досить легко та підтримувати кілька доменів верхнього рівня (наприклад, com, org, net тощо).
Мерлін,

4
Щойно спробував це в IIS 7.5. Здається, працює нормально.
Пресвятий

2
У вас проблеми з кешуванням? Після налаштування web.config, перший веб-сайт переходить на відповідність штрафу, але другий повертає той самий заголовок, що і перший. Таким чином, домени не надто збігаються.
Airn5475

20

У Web.API цей атрибут можна додати, використовуючи інформацію Microsoft.AspNet.WebApi.Cors, детально описану на http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

У MVC ви можете створити атрибут фільтра, щоб виконати цю роботу за вас:

[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;
    }
}

Потім або ввімкніть його для певних дій / контролерів:

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

Або додайте його для всіх контролерів у Global.asax.cs

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

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

    // *snip* existing code
}

Чи знаєте ви, для яких версій .Net / MVC це працює?
Keab42

Я успішно використовую це в .net 4 / MVC 3 - наскільки мені відомо, він повинен працювати у вищих версіях, але може бути кращим способом реєстрації глобального фільтра в пізніших версіях MVC.
Роб Черч

просто зауважте лише його WEB API 2 рішення. не для WEB API 1.
Samih A

5

Прочитавши кожну відповідь і спробувавши їх, жодна з них мені не допомогла. Під час пошуку в іншому місці я виявив, що ви можете створити власний атрибут, який потім можна додати до свого контролера. Він перезаписує EnableCors і додає до них білі домени.

Це рішення працює добре, оскільки воно дозволяє вам розміщувати домени в білому списку в webconfig (налаштування додатків), замість того, щоб їх кодувати в атрибуті EnableCors на вашому контролері.

 [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);
        }
    }
}

Я знайшов цей посібник в Інтернеті, і він працював як принада:

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

Я думав, що кину це сюди для тих, хто потребує.


Це відповідь лише за посиланням. Будь ласка, поставте відповідь самостійно.
Відновити Моніку

1
Гаразд, я тут новачок, чи це більше схоже на те, що було б передбачено ??
Гельфа

3

Мені вдалося вирішити це в коді обробки запитів, дотримуючись порад від "monsur".

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

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);

Наприклад, це можна зробити у веб-формі. Просто використовуйте Request.Headers, коли вони доступні. І, якщо потрібно, використовуйте білий список, щоб фільтрувати лише дозволені домени.
AFract

3
Це так само добре, як додати <add name = "Access-Control-Allow-Origin" value = "*" /> у файл web.config
Isaiah4110,

3

Для IIS 7.5+ ви можете використовувати модуль IIS CORS: https://www.iis.net/downloads/microsoft/iis-cors-module

Ваш web.config має бути приблизно таким:

<?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>

Ви можете знайти посилання на конфігурацію тут: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference


Якщо це працює так, як сказано, працює, я б хотів, щоб ви це розмістили 3 роки тому! Ого!
Майкл

2

Загляньте в бібліотеку Thinktecture IdentityModel - вона має повну підтримку CORS:

http://brockallen.com/2012/06/28/cors-support-in-webapi-mvc-and-iis-with-thinktecture-identitymodel/

І він може динамічно випромінювати ACA-Origin, який ви хочете.


Це здається справді корисною бібліотекою. Дякуємо за посилання.
Сем

1

Ви можете додати цей код до свого проекту asp.net webapi

у файлі 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");
    }
}

0

Ви можете використовувати Owin проміжне програмне забезпечення для визначення політики щодо корсів, в якій ви можете визначити кілька джерел корсів

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);
                }
            }
        };

-3

Вам потрібно лише:

  • додайте Global.asax до свого проекту,
  • видалити <add name="Access-Control-Allow-Origin" value="*" />з вашого web.config.
  • потім додайте це у Application_BeginRequestметоді Global.asax:

    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();
    }

Я сподіваюся, що це допоможе. що працюють для мене.


Додавання "...- Origin: *" працює, крім випадків, коли ви дозволяєте облікові дані. Якщо у вас є допустимі облікові дані, встановлені в true, тоді вам потрібно вказати домен (а не просто *). Саме в цьому полягає суть цієї проблеми. В іншому випадку ви можете просто вказати "... allow-credentials: false" і закінчити з цим.
Річард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.