ความปลอดภัยข้ามโดเมน OAuth ป๊อปอัป React.js


12

ฉันสนใจที่จะใช้ OAuth ใน React โดยใช้ป๊อปอัพ ( window.open)

เช่นฉันมี:

  1. mysite.com - นี่คือที่ฉันเปิดป๊อปอัพ
  2. passport.mysite.com/oauth/authorize - ป๊อปอัพ.

คำถามหลักคือวิธีการสร้างการเชื่อมต่อระหว่างwindow.open(ป๊อปอัพ) และwindow.opener(เนื่องจากเป็นที่รู้จักกันว่า window.opener นั้นเป็นโมฆะเนื่องจากความปลอดภัยข้ามโดเมนดังนั้นเราจึงไม่สามารถใช้งานได้อีกต่อไป)

window.openerจะถูกลบเมื่อใดก็ตามที่คุณนำทางไปยังโฮสต์อื่น (เพื่อเหตุผลด้านความปลอดภัย) ไม่มีวิธีแก้ไข ตัวเลือกเดียวควรทำการชำระเงินในเฟรมถ้าเป็นไปได้ เอกสารด้านบนต้องอยู่ในโฮสต์เดียวกัน

โครงการ:

ป้อนคำอธิบายรูปภาพที่นี่

การแก้ปัญหาที่เป็นไปได้:

  1. ตรวจสอบหน้าต่างที่เปิดใช้setIntervalอธิบายไว้ที่นี่
  2. ใช้cross-storage (ไม่คุ้มค่ากับมัน)

ดังนั้นวิธีที่ดีที่สุดที่แนะนำในปี 2019 คืออะไร?

แรปเปอร์สำหรับทำปฏิกิริยา - https://github.com/Ramshackle-Jamathon/react-oauth-popup


2
ในปี 2019 การสนับสนุนการจัดเก็บในพื้นที่นั้นดีกว่ามาก ฉันจะไปกับวิธี localStorage (อธิบายไว้ในstackoverflow.com/questions/18625733/ … ) เพราะมันดูเหมือนจะไม่เป็นวิธีแก้ปัญหามาก หน้าต่างหลักไม่จำเป็นต้องตรวจสอบสถานะของหน้าต่างลูกเป็นระยะ setIntervalสามารถใช้เป็นทางเลือกสำหรับ localStorage
Khanh ถึง

@ KhanhTO ใช่ฉันเห็นด้วยกับคุณอย่างสมบูรณ์localStorageแต่มันใช้งานได้กับโดเมนเดียวกันเท่านั้นดังนั้นมันจึงใช้งานไม่ได้ในสภาพของฉัน
Arthur

2
หลังจากคุณจบด้วย OAuth หน้าต่างลูกจะถูกเปลี่ยนเส้นทางกลับไปยังโดเมนของคุณคุณอยู่ในโดเมนเดียวกันตอนนี้กับผู้ปกครอง
Khanh ถึง

@KhanhTO อืมนี่เป็นความคิดที่ยอดเยี่ยม! ฉันควรจะรู้ ..
อาร์เธอร์

1
มันจะดียิ่งขึ้นถ้าเบราว์เซอร์กู้คืนwindow.openerหลังจากเปลี่ยนเส้นทางกลับไปที่โดเมนของเรา แต่นี่ไม่ใช่กรณี
Khanh ถึง

คำตอบ:


6

แนะนำโดยKhanh TO OAuth ป๊อปอัปด้วย localStorage ขึ้นอยู่กับการตอบสนอง-OAuth ป๊อปอัพ

โครงการ:

ป้อนคำอธิบายรูปภาพที่นี่

รหัส:

oauth-popup.tsx:

import React, {PureComponent, ReactChild} from 'react'

type Props = {
  width: number,
  height: number,
  url: string,
  title: string,
  onClose: () => any,
  onCode: (params: any) => any,
  children?: ReactChild,
}

export default class OauthPopup extends PureComponent<Props> {

  static defaultProps = {
    onClose: () => {},
    width: 500,
    height: 500,
    url: "",
    title: ""
  };

  externalWindow: any;
  codeCheck: any;

  componentWillUnmount() {
    if (this.externalWindow) {
      this.externalWindow.close();
    }
  }

  createPopup = () => {
    const {url, title, width, height, onCode} = this.props;
    const left = window.screenX + (window.outerWidth - width) / 2;
    const top = window.screenY + (window.outerHeight - height) / 2.5;

    const windowFeatures = `toolbar=0,scrollbars=1,status=1,resizable=0,location=1,menuBar=0,width=${width},height=${height},top=${top},left=${left}`;

    this.externalWindow = window.open(
        url,
        title,
        windowFeatures
    );

    const storageListener = () => {
      try {
        if (localStorage.getItem('code')) {
          onCode(localStorage.getItem('code'));
          this.externalWindow.close();
          window.removeEventListener('storage', storageListener);
        }
      } catch (e) {
        window.removeEventListener('storage', storageListener);
      }
    }

    window.addEventListener('storage', storageListener);

    this.externalWindow.addEventListener('beforeunload', () => {
      this.props.onClose()
    }, false);
  };

  render() {
    return (
      <div onClick={this.createPopup)}>
        {this.props.children}
      </div>
    );
  }
}

app.tsx

import React, {FC} from 'react'

const onCode = async (): Promise<undefined> => {
  try {
    const res = await <your_fetch>
  } catch (e) {
    console.error(e);
  } finally {
    window.localStorage.removeItem('code'); //remove code from localStorage
  }
}

const App: FC = () => (
  <OAuthPopup
    url={<your_url>}
    onCode={onCode}
    onClose={() => console.log('closed')}
    title="<your_title>">
    <button type="button">Enter</button>
  </OAuthPopup>
);

export default App;

3

ฉันเคยพบปัญหาในการเข้าสู่ระบบ oauth ของฉันกับข้อผิดพลาด window.open/window.opener บน ms-edge

กระแสของฉันก่อนที่ปัญหานี้คือ

  • ที่ปุ่มเข้าสู่ระบบคลิกที่เปิดป๊อปอัพ
  • หลังจากล็อกอินสำเร็จแอป oauth จะเปลี่ยนเส้นทางไปยังหน้าโดเมนของฉัน
  • จากนั้นฉันเรียกใช้ฟังก์ชันของหน้าต่างพาเรนต์ด้วยด้วยในป๊อปอัพ (window.opener.fn) ด้วยข้อมูลจากการตอบสนอง oauth และหน้าต่างหลักจากนั้นปิดหน้าต่างป๊อปอัพลูก

กระแสของฉันหลังจากปัญหานี้คือ

  • ที่ปุ่มเข้าสู่ระบบคลิกที่เปิดป๊อปอัพ
  • สร้าง setinterval ในกรณี (window.opener ไม่ได้กำหนดไว้)
  • หลังจากล็อกอินสำเร็จแอป oauth จะเปลี่ยนเส้นทางไปยังหน้าโดเมนของฉัน
  • ตรวจสอบว่า window.opener ใช้งานได้หรือไม่ให้ทำ # 3 จากโฟลว์ด้านบนและ clearInterval
  • หาก window.opener ไม่สามารถใช้งานได้เนื่องจากฉันอยู่ในหน้าโดเมนของฉันฉันพยายามตั้งค่า localstorage และพยายามอ่าน localstorage จากภายในฟังก์ชั่น setInterval ในหน้าต่างหลักแล้วล้าง localstorage และ setInterval และดำเนินการต่อ
  • (สำหรับความเข้ากันได้แบบย้อนหลัง) หาก localstorage ยังไม่พร้อมใช้งานให้ตั้งค่าคุกกี้ฝั่งไคลเอ็นต์ด้วยข้อมูลที่มีเวลาสั้น (5-10 วินาที) และลองอ่านคุกกี้ (document.cookie) ภายในฟังก์ชัน setInterval ในหน้าต่างหลักและ ดำเนินดำเนินการต่อ.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.