정보실

웹학교

정보실

html 타이밍 공격으로 Chrome 76에서 시크릿 모드 감지

본문

tl; dr : 시크릿 모드에서는 FileSystem API 쓰기가 훨씬 빠르고 시끄럽기 때문에 웹 사이트에서 시크릿 방문자를 기록 속도를 벤치 마킹하여 감지 할 수 있습니다. 결과


https://blog.jse.li/posts/chrome-76-incognito-filesystem-timing/ 


배경 


Chrome 76은 FileSystem API를 시크릿 모드에서 사용할 수 있도록 하여 웹 사이트가 API 존재 여부에 따라 시크릿 사용자를 감지하지 못하게 합니다.


시크릿 모드에서 Chrome은 API에 기록 된 데이터를 일반 모드에서 처럼 디스크에 유지하는 대신 메모리에 저장합니다. 우리가 메모리를 사용하기로 결정했을 때, 우리는 몇 가지 장단점이 있습니다 : RAM은 임시 저장소이므로 시크릿을 위한 매력적인 매체입니다. 그러나 부작용으로는 디스크보다 공간이 작고 속도가 빠릅니다.


최근 보안 연구원 Vikas Mishra는 API가 사용할 수 있는 공간의 양에 따라 시크릿 상태를 유추 할 수 있음을 발견했습니다.


이 블로그 게시물에서는 웹 사이트에서 API 쓰기 속도를 측정하여 시크릿 사용자를 감지하는 데 사용할 수 있는 기술에 대한 개념 증명을 제시합니다.


방법 


설정은 비교적 간단합니다. 큰 문자열을 반복해서 작성하고 시간이 얼마나 걸리는지 측정하여 파일 시스템을 벤치마킹 하십시오. 메모리는 디스크보다 빠르기 때문에 사이트 방문자가 시크릿 상태인지 여부를 속도로 알 수 있어야 합니다.


코드는 부록에 있습니다. GitHub에서 전체 소스를 보거나 내 결과를 복제하려면 직접 실행하십시오.


결과 


각각 벤치 마크를 100 회 이상 반복하면 (몇 분이 소요됨) 디스크에 대한 쓰기가 엄청나게 복잡하고 메모리에 쓰는 것보다 최대 3-4 배 더 오래 걸린다는 것을 알 수 있습니다.

Line chart showing normal vs. incognito write timings 


타이밍의 히스토그램은 비슷한 이야기를 합니다. 시크릿 쓰기 속도는 왼쪽으로 밀집되어 있지만 일반 모드에서는 쓰기 속도가 크게 다릅니다. 평균 및 표준 편차와 같은 기본 통계를 계산하여 방문자가 시크릿 상태인지 여부를 합리적인 확실하게 식별 할 수 있어야 합니다. 측정 결과 시크릿 모드에서 평균 벤치 마킹 시간은 약 792ms이며 일반 모드의 2281ms와 비교하여 2.8 배 더 깁니다. 시크릿 모드에서는 표준 편차가 67ms로, 일반 모드에서는 1183ms로 17.7 배 더 넓어집니다.

Histogram of normal and incognito write timing distributions 


전체 데이터는 여기에서 확인할 수 있습니다.


한계 


이 타이밍 공격은 몇 킬로바이트의 데이터 복사와 같은 빠른 작업에서 정확한 통계를 얻기 위해 많은 측정을 수행하는 데 달려 있습니다. 즉, 모든 데이터가 작동하는 기존 기술보다 훨씬 느린 충분한 데이터를 얻는 데 몇 분에서 수십 초가 걸립니다. 거의 즉시.


또한 공격의 효과는 하드웨어 구성에 따라 다릅니다. 컴퓨터와 스마트 폰의 CPU, 메모리 및 디스크 속도는 모두 타이밍에 영향을 미칩니다. 장치에서 실행되는 백그라운드 프로세스도 노이즈를 유발할 수 있습니다. 파일을 복사하거나 다운로드하거나, 다른 탭에서 비디오를 재생하거나, 앱을 시작하면 결과가 어쨌든 왜곡 될 수 있습니다.


마지막 제한 사항은 공격이 실제로 시크릿 모드를 감지하지 못한다는 것입니다. 시크릿 모드를 감지하기 위한 적절한 프록시로 밝혀지는 FileSystem API의 백업 저장소를 감지합니다. 라이브 USB 또는 tmpfs에 저장된 Chrome 프로필과 같이 디스크가 메모리 인 상황에서는 오 탐지를 유발할 수 있습니다. 그러한 구성은 추적을 우회 하려는 시도이며, 그것들을 인식 할 수 없는 것으로 만들 수 있습니다.


결론적으로,이 기술은 속도가 느리고 신뢰성이 떨어지지 만 디스크 대신 메모리에 데이터를 저장하려는 근본적인 기술적 결정을 공격하기 때문에 기존 방법보다 패치하기가 더 어렵다는 것입니다.


완화 


이 공격을 막는 유일한 방법은 시크릿 모드와 일반 모드 모두 동일한 저장 매체를 사용하여 API가 동일한 속도로 실행되도록 하는 것입니다.


Chrome 개발자는 2018 년 3 월의 디자인 문서에서 타이밍 및 할당량에 대한 공격의 위험을 식별하고 내 공격과 Mishra의 공격을 막을 수 있는 대체 구현을 설명했습니다.


또는 메타 데이터 만 메모리에 보관하고 파일을 디스크에 암호화 할 수 있습니다. 이는 인 메모리와 디스크 백업 스토리지를 구별하기 위해 타이밍을 사용하는 사이트의 위험을 해결하고 사용 가능한 할당량과 파일 시스템 유형 (일시적 대 영구)의 차이를 제거합니다. 


그러나 이러한 솔루션에는 자체 장단점이 있습니다. 공격에 강하지 만 메타 데이터는 남습니다. 데이터 자체를 해독 할 수 없는 경우에도 데이터의 존재는 시크릿 사용의 증거를 제공하며 사용자가 시크릿 모드를 마지막으로 사용했을 때 유출되고 디스크에 쓴 데이터의 대략적인 크기입니다.


시크릿 모드의 위협 모델을 고려하는 경우 기본 목적은 방문하는 웹 사이트의 개인 정보가 아닌 동일한 기기의 다른 사용자로부터 개인 정보를 제공하는 것입니다. 그 절충은 그만한 가치가 없으며 실제로 시크릿 모드가 해결하려는 문제에 대한 약한 솔루션입니다.

Incognito mode New Tab page 


부록


내 PoC 코드는 무작위로 생성 된 문자열을 FileSystem API에 쓰는 몇 가지 루프입니다. 여기에 전체 소스 코드가 있습니다. 타이밍 공격 작성 또는 디스크 / 메모리 벤치마킹 경험이 있는 경우 PR, 문제 및 팁을 환영합니다.


const largeStrings = [
  // These strings are 5000 characters long. I generated them by running
  // base64 /dev/urandom -w 0 | head -c 5000
  'odE141SCRsNhfNBb95VhqRubp+fXTF1Dricc0G9wWrQcXRvu3uhGRh4t2TiUZF1BdSKLOrnG...',
  'pdfhLvvnkBGjbuR1/0WcCcM2li/cYOQ/wZGPAofjBXxo6PvhoEAWYtEMtTlbcLm+dPxwQFm8...',
  'Xfo5aKCHnIQc9zMtUWmGYiwzBJuDQLEVyg0t9ID2ZsCVMnVD7h8juo9Bmd+e2VdmofvGkFoa...',
  'jsYalJDnye4x5Vvl9w+F7aRrVx+WcJT5E7rzB9UNxb7iyY+mFAvsllN95ZDom50+GhhBuT+l...',
  'QcaZ/f91np7UkMvy4jrJks5Iogpgik0JZA0kCeXEPc2vdFYHKKIVT+nKmrva0qUee14LXh9Y...'
]
const SIZE = 6*1024*1024 // 6 MB
// Completely arbitrary numbers. Probably make them as high as you can tolerate:
const NUM_BENCHMARK_ITERATIONS = 200
const NUM_MEASUREMENTS = 100

const writeToFile = (fs, data) => {
  return new Promise((resolve) => {
    fs.root.getFile('data', { create: true }, (fileEntry) => {
      fileEntry.createWriter((fileWriter) => {
        fileWriter.onwriteend = resolve

        var blob = new Blob([data], { type: 'text/plain' });
        fileWriter.write(blob);
      })
    })
  })
}

const runBenchmark = async (fs) => {
  const time = new Date()
  for (let i = 0; i < NUM_BENCHMARK_ITERATIONS; i++) {
    for (let j = 0; j < largeStrings.length; j++) {
      await writeToFile(fs, largeStrings[j])
    }
  }
  return new Date() - time
}

const onInitFs = async (fs) => {
  const timings = []
  for (let i = 0; i < NUM_MEASUREMENTS; i++) {
    timings.push(await runBenchmark(fs))
  }

  console.log(timings)
}

window.webkitRequestFileSystem(window.TEMPORARY, SIZE, onInitFs)



페이지 정보

조회 134회 ]  작성일19-08-19 10:19

웹학교