จะข้ามคำขอไฟล่วงหน้า OPTIONS ได้อย่างไร


93

ฉันได้พัฒนาแอพ PhoneGap ซึ่งตอนนี้เปลี่ยนเป็นเว็บไซต์บนมือถือแล้ว ทุกอย่างทำงานได้อย่างราบรื่นนอกเหนือจากความผิดพลาดเล็ก ๆ น้อย ๆ ฉันใช้ API ของบุคคลที่สามผ่านคำขอ POST ซึ่งทำงานได้ดีในแอป แต่ล้มเหลวในเวอร์ชันเว็บไซต์บนอุปกรณ์เคลื่อนที่

หลังจากดูใกล้ ๆ ดูเหมือนว่า AngularJS (ฉันเดาว่าเบราว์เซอร์จริง) เป็นครั้งแรกที่ส่งคำขอ OPTIONS วันนี้ฉันได้เรียนรู้มากมายเกี่ยวกับ CORS แต่ดูเหมือนจะไม่รู้วิธีปิดการใช้งานทั้งหมด ฉันไม่มีสิทธิ์เข้าถึง API นั้น (ดังนั้นการเปลี่ยนแปลงที่ด้านนั้นจึงเป็นไปไม่ได้) แต่พวกเขาได้เพิ่มโดเมนที่ฉันกำลังทำงานอยู่ในส่วนหัว Access-Control-Allow-Origin

นี่คือรหัสที่ฉันกำลังพูดถึง:

        var request = {
                language: 'fr',
                barcodes: [
                    {
                        barcode: 'somebarcode',
                        description: 'Description goes here'
                    }
                ]
            };
        }
        var config = {
            headers: { 
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/json'
            }
        };
        $http.post('http://somedomain.be/trackinginfo', request, config).success(function(data, status) {
            callback(undefined, data);
        }).error(function(data, status) {
            var err = new Error('Error message');
            err.status = status;
            callback(err);
        });

ฉันจะป้องกันไม่ให้เบราว์เซอร์ (หรือ AngularJS) ส่งคำขอ OPTIONS และข้ามไปยังคำขอ POST จริงได้อย่างไร ฉันใช้ AngularJS 1.2.0

ขอบคุณล่วงหน้า.

คำตอบ:


101

พรีapplication/jsonไลต์กำลังถูกเรียกใช้โดยประเภทเนื้อหาของ วิธีที่ง่ายที่สุดในการป้องกันปัญหานี้คือตั้งค่า Content-Type text/plainในกรณีของคุณ application/x-www-form-urlencodedและmultipart/form-dataประเภทเนื้อหาก็ยอมรับได้ แต่แน่นอนว่าคุณจะต้องจัดรูปแบบเพย์โหลดคำขอของคุณให้เหมาะสม

หากคุณยังคงเห็นแสงนำหน้าหลังจากทำการเปลี่ยนแปลงแล้ว Angular อาจกำลังเพิ่ม X-header ในคำขอด้วย

หรือคุณอาจมีส่วนหัว (Authorization, Cache-Control ... ) ที่จะเรียกใช้โปรดดู:


9
นี่คือคำตอบที่ถูกต้อง - ส่วนหัว Content-Type และ Cache-Control ของคุณกำลังเรียกใช้คำขอ preflight GET ธรรมดาที่มีประเภทเนื้อหาเป็นข้อความ / ธรรมดาและอื่น ๆ อีกสองสามวิธีเป็นวิธีเดียวในการเรียกใช้คำขอที่ไม่ได้ระบุไว้ล่วงหน้า ดู: developer.mozilla.org/en-US/docs/HTTP/…
Jeff Hubbard

ใช่ลืมเกี่ยวกับ Cache-Control
Ray Nicholus

17
ส่วนหัวที่กำหนดเองจะทริกเกอร์ไฟหน้า
Sébastien Deprez

2
การเปลี่ยนประเภทเนื้อหาเพื่อป้องกันการทดสอบ OPTION ไม่ใช่คำตอบ ประเภทเนื้อหาควรตรงกับประเภทเนื้อหาโดยไม่คำนึงถึง
ekerner

หากเบราว์เซอร์ขว้าง & ในแบ็กเอนด์วิธีการ Http OPTIONS ถูกบล็อกจะมีผลหรือไม่เช่นเบราว์เซอร์จะไม่เรียก API ที่เกี่ยวข้องสำหรับ POST / PUT เนื่องจาก OPTIONS ล้มเหลว
P Satish Patro

16

ดังที่ Ray พูดคุณสามารถหยุดได้โดยการแก้ไขส่วนหัวของเนื้อหาเช่น -

 $http.defaults.headers.post["Content-Type"] = "text/plain";

ตัวอย่างเช่น -

angular.module('myApp').factory('User', ['$resource','$http',
    function($resource,$http){
        $http.defaults.headers.post["Content-Type"] = "text/plain";
        return $resource(API_ENGINE_URL+'user/:userId', {}, {
            query: {method:'GET', params:{userId:'users'}, isArray:true},
            getLoggedIn:{method:'GET'}
        });
    }]);

หรือโทรโดยตรง -

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'text/plain'
 },
 data: { test: 'test' }
}

$http(req).then(function(){...}, function(){...});

สิ่งนี้จะไม่ส่งคำขอตัวเลือกก่อนการบินใด ๆ

หมายเหตุ:คำขอไม่ควรมีพารามิเตอร์ส่วนหัวที่กำหนดเองหากส่วนหัวของคำขอมีส่วนหัวที่กำหนดเองเบราว์เซอร์จะทำการร้องขอก่อนการบินคุณจะไม่สามารถหลีกเลี่ยงได้


1
ควรทำอย่างไรกับ$http?
เรียน

ขอบคุณที่คล้ายกับที่ฉันทำ การเปลี่ยนแปลงเพียงอย่างเดียวคือวิธีการGETและส่วนหัวAuthorizationเพิ่มเติม แต่ยังส่งพรีไลท์.
เรียน

1
คุณสามารถวางคำขอของคุณที่นี่ได้ไหม เป็นขดหรืออะไร? อาจเป็นเพราะ Authorization header ให้ลองเอาออกแล้วลอง หากคุณกำลังส่งส่วนหัวที่กำหนดเองเชิงมุมจะส่งคำขอก่อนการบิน
vivex

pastebin.com/vRDeFiH2 อย่างแรกคือคำขอถึง $ http และคำขอที่สองคือคำขอที่ถูกต้องซึ่งสร้างโดยบุรุษไปรษณีย์ :)
เรียน

2

เมื่อดำเนินการตามคำขอ AJAX ข้ามโดเมนบางประเภทเบราว์เซอร์สมัยใหม่ที่รองรับ CORS จะแทรกคำขอ "preflight" พิเศษเพื่อพิจารณาว่าพวกเขามีสิทธิ์ในการดำเนินการหรือไม่ จากตัวอย่างแบบสอบถาม:

$http.get( ‘https://example.com/api/v1/users/’ +userId,
  {params:{
           apiKey:’34d1e55e4b02e56a67b0b66’
          }
  } 
);

จากผลของส่วนนี้เราจะเห็นว่าที่อยู่ถูกส่งสองคำขอ (OPTIONS และ GET) การตอบสนองจากเซิร์ฟเวอร์รวมถึงส่วนหัวที่ยืนยันการอนุญาตให้รับแบบสอบถาม หากเซิร์ฟเวอร์ของคุณไม่ได้กำหนดค่าให้ประมวลผลคำขอ OPTIONS อย่างถูกต้องคำขอของไคลเอ็นต์จะล้มเหลว ตัวอย่างเช่น:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: accept, origin, x-requested-with, content-type
Access-Control-Allow-Methods: DELETE
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Methods: GET
Access-Control-Allow-Methods: POST
Access-Control-Allow-Orgin: *
Access-Control-Max-Age: 172800
Allow: PUT
Allow: OPTIONS
Allow: POST
Allow: DELETE
Allow: GET

2

ฉันคิดว่าวิธีที่ดีที่สุดคือตรวจสอบว่าคำขอเป็นประเภท "OPTIONS" คืน 200 จากเครื่องกลางหรือไม่ มันได้ผลสำหรับฉัน

express.use('*',(req,res,next) =>{
      if (req.method == "OPTIONS") {
        res.status(200);
        res.send();
      }else{
        next();
      }
    });

ใช้งานได้ แต่ใน OWASP ขอแนะนำว่าอย่าให้ OPTIONS คุณบล็อกสภาพอากาศในบริการแบ็กเอนด์ / โฮสต์ (Nginx, Apache) เป็นต้น
P Satish Patro

0

Preflight เป็นคุณลักษณะความปลอดภัยของเว็บที่ใช้งานโดยเบราว์เซอร์ สำหรับ Chrome คุณสามารถปิดใช้งานการรักษาความปลอดภัยเว็บทั้งหมดได้โดยเพิ่มแฟล็ก --disable-web-security

ตัวอย่างเช่น "C: \ Program Files \ Google \ Chrome \ Application \ chrome.exe" --disable-web-security --user-data-dir = "C: \ newChromeSettingsWithoutSecurity" ก่อนอื่นคุณสามารถสร้างทางลัดใหม่ของ Chrome ไปที่คุณสมบัติและเปลี่ยนเป้าหมายตามด้านบน สิ่งนี้น่าจะช่วยได้!


คุณไม่สามารถคาดหวังว่า OP จะบอกให้ลูกค้าของเขาปิดการรักษาความปลอดภัยของเบราว์เซอร์เพียงเพื่อเปิดใช้งานคุณสมบัติใช่ไหม!
svarog

@svarog ส่วนใหญ่มีวัตถุประสงค์เพื่อการพัฒนาส่วนใหญ่บนเซิร์ฟเวอร์ที่ใช้งานจริงคุณจะไม่ประสบปัญหานี้
อารีจิตภัทรา

หากเบราว์เซอร์ขว้าง & ในแบ็กเอนด์วิธีการ Http OPTIONS ถูกบล็อกจะมีผลหรือไม่เช่นเบราว์เซอร์จะไม่เรียก API ที่เกี่ยวข้องสำหรับ POST / PUT เนื่องจาก OPTIONS ล้มเหลว
P Satish Patro

-2

การตั้งค่าประเภทเนื้อหาเป็นไม่ได้กำหนดจะทำให้จาวาสคริปต์ส่งผ่านข้อมูลส่วนหัวตามที่เป็นอยู่และเขียนการกำหนดค่าส่วนหัว $ httpProvider เชิงมุมเริ่มต้น เอกสาร Angular $ http

$http({url:url,method:"POST", headers:{'Content-Type':undefined}).then(success,failure);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.