XSS注入我也不怕不怕啦--PHP从框架层面屏蔽XSS的思考和实践
本文由腾讯WeTest团队提供,更多资讯可直接戳链接查看: http://wetest.qq.com/lab/微信号:TencentWeTest
对于新接触web开发的同学来说,XSS注入是一件非常头疼的事情。就算是web开发多年的老手,也不敢保证自己写的代码完全没有XSS注入的风险。
因为现在比较主流的XSS防治手段主要有两种,一种是在用户输入是将异常关键词过滤,另一种则是在页面渲染时将html内容实体化转义。
然而第一种方法一定程度上对业务数据要求相对较高,存在屏蔽数据和业务数据有冲突的情况,例如“程序类帮助文档的编辑保存”,“外站帖子爬虫”等等。都不能无差别将异常关键词过滤掉,必须保持原输入内容的完整性。
而另一种html内容实体化的方式,又非常的依赖开发的编程习惯。一个不小心漏写了就是一个安全工单,做web的前端同事应该深有体会。于是,我开始研究能不能不再依赖开发习惯,从框架层面上完全屏蔽XSS。
这里先介绍一下我的PHP web Server框架,是我自己从从事web开发开始就一直在维护更新的框架,链接在此,有兴趣的同学,可以看下。或者提出更多改进的建议。
首先来看下普通的PHP是怎么转义html实体的:
htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE)ENT_QUOTES 意思是需要转义双引号(”)和 单引号 (’)
ENT_SUBSTITUTE 意思是 把无效的编码替代成一个指定的带有 Unicode 替代字符
首先很容易想到的是把php模版中的字符串全部替换掉。
而熟悉smarty的同学应该知道,其实smarty的模版渲染也是用了转义字符串的方式。那我们渲染页面的代码可以这么写。
/*** 获得模板渲染后的内容* @return string*/public function getContent(){//防XSS注入foreach ( [Math Processing Error]
param) { [Math Processing Error]param) ? htmlspecialchars( [Math Processing Error]param;}unset($param);extract($this->params); ob_start(); //include template $file = sprintf('%s/template/%s.tpl.php', TXApp::$app_root, $this->view); include $file; $content = ob_get_clean(); return $content;}
这样的话,传入的字符串类型的变量都会被替换掉了。但是问题也很明显。那就是如果是数组或者object对象,里面的内容就无法进行转义了。而这同样也是smarty的一个弊端,smarty是在assign方法里进行的实体化转义,如果是数组或者object就无视了。当然我们还需要更进一步的进行转义处理。
有同学看到这里肯定会有个想法,如果是数组的话,递归进行转义处理不就可以了吗。
事实上我一开始的确是这么做的,但是弊端也很明显。递归的层数越多,性能损耗就越大。而且并非所有进行转义的内容我们都会用到,这样就会造成性能的浪费。最优化的处理方式就是当需要用到的时候再做转义处理,没用到的时候该咋样还是咋样。
于是我开始着手自己写一个类,在我的框架里我命名为TXArray 继承了ArrayObject,也就是让其具备了array的部分性质。接下来开始进行array 方法重构。以下是部分代码
class TXArray extends ArrayObject{private [Math Processing Error]
encodes = [];public function __construct($storage=array()){ $this->storage = $storage;}public function getIterator(){ foreach ($this->storage as $key => $value){ $key = $this->encode($key); if (!isset($this->encodes[$key])){ $this->encodes[$key] = $this->encode($value); } } return new ArrayIterator($this->encodes);}public function offsetGet($k){ if (isset($this->storage[$k])){ $key = $this->encode($k); if (!isset($this->encodes[$key])){ $this->encodes[$key] = $this->encode($this->storage[$k]); } return $this->encodes[$key]; } return null;}public function offsetExists($k){ return isset($this->storage[$k]);}public function offsetUnset($k){ unset($this->storage[$k]); $k = $this->encode($k); unset($this->encodes[$k]);}public function offsetSet($k, $value){ $this->storage[$k] = $value; $this->encodes[$k] = $this->encode($value);}public function count(){ return count($this->storage);}private function encode($value){ if (is_string($value)){ $value = is_string($value) ? htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE) : $value } elseif (is_array($value)){ $value = new self($value); } return $value;}
}offsetGet 会在 [Math Processing Error]
key] 时候被调用。getIterator() 方法则是在 foreach循环时被调用。当发现内部参数是个array时,会再次递归调用自己,重复上述步骤。效果如下图所示:这样一个递归的转义模型就写好了。也实现了用到时才转义的目标。
但是还有个问题。并不是所有字段都需要转义的,例如我们平台的舆情监控数据,数据来源主要是各大贴吧论坛,数据本身包含了图片img,字体颜色等html元素。在展示时并不希望被模版转义。所以我在框架上继续优化。添加了PHP的魔法方法__get()
public function __get($k){ return isset($this->storage[$k]) ? $this->storage[$k] : null;}public function get($key){ return $this->__get($key);}
也就是说只要调用 [Math Processing Error]
array->get(0) 就可以直接获取原来的数据而不进行转义了。另外看业务也再需要加上一些对array的处理方法,例如array_key_exists,in_array, join等。或者直接使用__call() 魔法方法
public function __call($method, $args){ $args[] = &$this->storage; return call_user_func_array($method, $args);}public function serialize(){ return serialize($this->storage);}public function __invoke(){ return $this->storage ? true : false;}public function keys(){ return array_keys($this->values(false));}
然后我们在页面模版里就可以愉快的使用了
但是这个TXArray还是有个问题,就是如果需要转化成json全部下发给js使用的话,那里面的数据就无法被转义了。当然也可以递归先全转义一遍,但总觉得代码不够漂亮。这个问题我还会继续研究。有新的进展和优化我都会上传到我的 PHP开源组件框架 中,大家有什么好的建议都可以rtx跟我探讨沟通哈
本文由腾讯WeTest团队提供,更多资讯可直接戳链接查看: http://wetest.qq.com/lab/微信号:TencentWeTest

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Alipay PHP ...

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

세션 납치는 다음 단계를 통해 달성 할 수 있습니다. 1. 세션 ID를 얻으십시오. 2. 세션 ID 사용, 3. 세션을 활성 상태로 유지하십시오. PHP에서 세션 납치를 방지하는 방법에는 다음이 포함됩니다. 1. 세션 _regenerate_id () 함수를 사용하여 세션 ID를 재생산합니다. 2. 데이터베이스를 통해 세션 데이터를 저장하십시오.

PHP 개발에서 견고한 원칙의 적용에는 다음이 포함됩니다. 1. 단일 책임 원칙 (SRP) : 각 클래스는 하나의 기능 만 담당합니다. 2. Open and Close Principle (OCP) : 변경은 수정보다는 확장을 통해 달성됩니다. 3. Lisch의 대체 원칙 (LSP) : 서브 클래스는 프로그램 정확도에 영향을 미치지 않고 기본 클래스를 대체 할 수 있습니다. 4. 인터페이스 격리 원리 (ISP) : 의존성 및 사용되지 않은 방법을 피하기 위해 세밀한 인터페이스를 사용하십시오. 5. 의존성 반전 원리 (DIP) : 높고 낮은 수준의 모듈은 추상화에 의존하며 종속성 주입을 통해 구현됩니다.

시스템이 다시 시작된 후 UnixSocket의 권한을 자동으로 설정하는 방법. 시스템이 다시 시작될 때마다 UnixSocket의 권한을 수정하려면 다음 명령을 실행해야합니다.

phpstorm에서 CLI 모드를 디버그하는 방법은 무엇입니까? PHPStorm으로 개발할 때 때때로 CLI (Command Line Interface) 모드에서 PHP를 디버그해야합니다 ...

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

기사는 입력 유효성 검사, 인증 및 정기 업데이트를 포함한 취약점을 방지하기 위해 프레임 워크의 필수 보안 기능을 논의합니다.
