目次
ThinkPHP フレームワークのセキュリティ実装分析、thinkphp フレームワークの実装
您可能感兴趣的文章:
ホームページ バックエンド開発 PHPチュートリアル ThinkPHP フレームワークのセキュリティ実装分析、thinkPHP フレームワーク実装_PHP チュートリアル

ThinkPHP フレームワークのセキュリティ実装分析、thinkPHP フレームワーク実装_PHP チュートリアル

Jul 12, 2016 am 08:57 AM
thinkphp thinkphp フレームワーク 安全性

ThinkPHP フレームワークのセキュリティ実装分析、thinkphp フレームワークの実装

ThinkPHP フレームワークは、中国で最も人気のある PHP フレームワークの 1 つですが、外国のフレームワークには匹敵しませんが、中国語のマニュアルが非常に包括的であるという利点があります。 。最近SQLインジェクションについて勉強しています。以前TPフレームワークを使用していたときは、基盤層がセキュリティ機能を提供していたため、開発プロセス中にセキュリティの問題をあまり考慮していませんでした。

1. I 関数について言いたいこと

TP システムは、入力変数をフィルタリングするための I 関数を提供します。関数本体全体の意味は、I('get.')、I('post.id') などのさまざまな形式でデータを取得し、(デフォルトでは) htmlspecialchars 関数を使用してそれを処理することです。

セキュリティ フィルタリングに他の方法を使用する必要がある場合は、/ThinkPHP/Conf/convention.php から設定できます:

リーリー

I 関数は /ThinkPHP/Common/functions.php から見つけることができます。ソース コードは次のとおりです。

リーリー

そうですね、この関数は基本的に 3 つの部分に分かれています:
最初のブロックは、さまざまな形式でデータを取得することです。
2 番目のブロック は、取得したデータが 2 次元配列であっても 3 次元配列であっても、ループ エンコードを実行することです。
最後から 2 番目の行である 3 番目のブロック は、think_filter を呼び出して、データに対する謎の処理の最後のステップを実行します。

まず think_filter 関数をトレースしましょう:

リーリー

この機能は非常にシンプルで、特定のキーワードの後に​​スペースを追加するだけです。

しかし、think_filter というこの関数はスペースを追加するだけで、どのようなフィルタリング効果を発揮しますか?

ユーザーがログインしているかどうか、ユーザーが特定の製品を購入できるかどうかなどの重要な論理検証は、サーバー側から検証する必要があることは誰もが知っていますが、フロントエンドから検証すれば簡単に行うことができます。バイパスされた。同じ理由で、プログラムでは、in/exp などの論理構造はサーバーによって最適に制御されます。

サーバーに渡されたデータが id[0]=in&id[1]=1,2,3 の場合、think_filter 関数が無い場合は以下の表の 1 に解析され、サーバーとみなして論理的に分析します。しかし、以下の表 2 のようになると、余分なスペースがあるため、照合および解析できなくなり、抜け穴を回避できます。

リーリー

2. SQL インジェクション

関連するファイルは、 /ThinkPHP/Library/Think/Db.class.php (3.2.3 では /ThinkPHP/Library/Think/Db/Driver.class.php に変更されました) および /ThinkPHP/Library/Think/Model です。クラス.php。 Model.class.php ファイルは、curd によって直接呼び出される関数を提供し、Driver.class.php の関数は、curd 操作によって間接的に呼び出されます。

リーリー

TP の処理アイデアについて大まかに話します:

最初に Model クラスをユーザー オブジェクトにインスタンス化し、次にユーザー オブジェクトの where 関数を呼び出して $map を処理します。つまり、$map で何らかの書式設定を実行し、それをユーザー オブジェクトのメンバー変数 $options に割り当てます (また、操作は SQL ステートメントを直接結合するのではなく、ユーザー オブジェクトの対応するメンバー変数に最初に割り当てられるため、連続した操作を記述する場合、SQL ステートメントの結合のようにキーワードの順序を考慮する必要はありません)、および次に、find 関数を呼び出します。

find 関数は、データを取得するためにドライバー クラス内の基礎となる関数を呼び出します。選択機能となると、また別の話になります。

curd 操作に加えて、select は pdo バインディングも処理します。ここでは curd 操作のみに関心があるため、select で buildSelectSql を呼び出してページング情報を処理し、parseSQL を呼び出して確立された順序で SQL ステートメントを組み立てます。

SQL ステートメントの結合に必要なパラメータはすべてメンバー変数に配置されていますが、その形式は統一されておらず、文字列形式、配列形式、または TP によって提供される特別なクエリ形式である可能性があります。 :$data['id']=array('gt','100'); のように、スプライシングの前に、統一された書式設定のためにそれぞれの処理関数を呼び出す必要があります。分析には複雑な例である parseWhere を選択しました。

セキュリティに関しては、I 関数を使用してデータを取得すると、デフォルトで htmlspecialchars 処理が実行され、XSS 攻撃に効果的に抵抗できますが、SQL インジェクションにはほとんど影響しません。

SQL インジェクションに関連するシンボルをフィルタリングする場合、TP のアプローチは非常に賢明です。最初に通常のロジックに従ってユーザーの入力を処理し、次に parseWhere、parseHaving、および最終的な SQL ステートメントに最も近いその他の関数で安全な処理を実行します。この順序により、処理中の注入が回避されます。

もちろん、最も一般的な処理方法はaddslashesです。ビーチで亡くなった元波によると、フィルタリングにはmysql_real_escape_stringを使用することが推奨されていますが、この機能はデータベースが接続されている場合にのみ使用できます。

結局のところ、ここまで到達した人は全員データベースに接続しているので、TP はこの領域を最適化できるような気がします。

さて、次に分析が始まります:

まず、Model オブジェクトのいくつかのメンバー変数について話しましょう:

リーリー

where 関数のロジックは非常に単純です。where('id=%d&name=%s',array($id,$name)) の形式の場合は、$id で mysql のscapeString を呼び出します。 $name 変数を扱います。 escapeString の本質は、処理のために mysql_real_escape_string、addslashes およびその他の関数を呼び出すことです。

最后将分析之后的数组赋值到Model对象的成员函数——$where中供下一步处理。

再分析find函数:

//model.class.php  行721  版本3.2.3
public function find($options=array()) {
  if(is_numeric($options) || is_string($options)){ /*如果传递过来的数据是字符串,不是数组*/
    $where[$this->getPk()] =  $options;
    $options        =  array();
    $options['where']    =  $where; /*提取出查询条件,并赋值*/
  }
  // 根据主键查找记录
  $pk = $this->getPk();
  if (is_array($options) && (count($options) > 0) && is_array($pk)) {
    /*构造复合主键查询条件,此处省略*/
  }
  $options['limit']  =  1;                 // 总是查找一条记录
  $options      =  $this->_parseOptions($options);   // 分析表达式
  if(isset($options['cache'])){
    /*缓存查询,此处省略*/
  }
  $resultSet = $this->db->select($options);
  if(false === $resultSet){  return false;}
  if(empty($resultSet)) {  return null; }      // 查询结果为空    
  if(is_string($resultSet)){  return $resultSet;}  //查询结果为字符串
  // 读取数据后的处理,此处省略简写
  $this->data = $this->_read_data($resultSet[0]);
  return $this->data;
}

ログイン後にコピー

$Pk为主键,$options为表达式参数,本函数的作用就是完善成员变量——options数组,然后调用db层的select函数查询数据,处理后返回数据。

跟进_parseOptions函数:

protected function _parseOptions($options=array()) { //分析表达式
  if(is_array($options)){
    $options = array_merge($this->options,$options);
  }
  /*获取表名,此处省略*/
  /*添加数据表别名,此处省略*/
  $options['model']    =  $this->name;// 记录操作的模型名称
  /*对数组查询条件进行字段类型检查,如果在合理范围内,就进行过滤处理;否则抛出异常或者删除掉对应字段*/
  if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])){
    foreach ($options['where'] as $key=>$val){
      $key = trim($key);
      if(in_array($key,$fields,true)){  //如果$key在数据库字段内,过滤以及强制类型转换之
        if(is_scalar($val)) { 
        /*is_scalar 检测是否为标量。标量是指integer、float、string、boolean的变量,array则不是标量。*/     
          $this->_parseType($options['where'],$key);
        }
      }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){
        // 如果$key不是数字且第一个字符不是_,不存在.(|&等特殊字符
        if(!empty($this->options['strict'])){  //如果是strict模式,抛出异常
          E(L('_ERROR_QUERY_EXPRESS_').':['.$key.'=>'.$val.']');
        }  
        unset($options['where'][$key]); //unset掉对应的值
      }
    }
  } 
  $this->options =  array();      // 查询过后清空sql表达式组装 避免影响下次查询
  $this->_options_filter($options);    // 表达式过滤
  return $options;
}

ログイン後にコピー

本函数的结构大概是,先获取了表名,模型名,再对数据进行处理:如果该条数据不在数据库字段内,则做出异常处理或者删除掉该条数据。否则,进行_parseType处理。parseType此处不再跟进,功能为:数据类型检测,强制类型转换包括int,float,bool型的三种数据。

函数运行到此处,就该把处理好的数据传到db层的select函数里了。此时的查询条件$options中的int,float,bool类型的数据都已经进行了强制类型转换,where()函数中的字符串(非数组格式的查询)也进行了addslashes等处理。

继续追踪到select函数,就到了driver对象中了,还是先列举几个有用的成员变量:

// 数据库表达式
protected $exp = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN','not in'=>'NOT IN','between'=>'BETWEEN','not between'=>'NOT BETWEEN','notbetween'=>'NOT BETWEEN');
// 查询表达式
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
// 当前SQL指令
protected $queryStr  = '';
// 参数绑定
protected $bind     =  array();
select函数:
public function select($options=array()) {
  $this->model =  $options['model'];
  $this->parseBind(!empty($options['bind'])&#63;$options['bind']:array());
  $sql  = $this->buildSelectSql($options);
  $result  = $this->query($sql,!empty($options['fetch_sql']) &#63; true : false);
  return $result;
}

ログイン後にコピー

版本3.2.3经过改进之后,select精简了不少。parseBind函数是绑定参数,用于pdo查询,此处不表。

buildSelectSql()函数及其后续调用如下:

public function buildSelectSql($options=array()) {
  if(isset($options['page'])) {
    /*页码计算及处理,此处省略*/
  }
  $sql =  $this->parseSql($this->selectSql,$options);
  return $sql;
}
/* 替换SQL语句中表达式*/
public function parseSql($sql,$options=array()){
  $sql  = str_replace(
    array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%LOCK%','%COMMENT%','%FORCE%'),
    array(
      $this->parseTable($options['table']),
      $this->parseDistinct(isset($options['distinct'])&#63;$options['distinct']:false),
      $this->parseField(!empty($options['field'])&#63;$options['field']:'*'),
      $this->parseJoin(!empty($options['join'])&#63;$options['join']:''),
      $this->parseWhere(!empty($options['where'])&#63;$options['where']:''),
      $this->parseGroup(!empty($options['group'])&#63;$options['group']:''),
      $this->parseHaving(!empty($options['having'])&#63;$options['having']:''),
      $this->parseOrder(!empty($options['order'])&#63;$options['order']:''),
      $this->parseLimit(!empty($options['limit'])&#63;$options['limit']:''),
      $this->parseUnion(!empty($options['union'])&#63;$options['union']:''),
      $this->parseLock(isset($options['lock'])&#63;$options['lock']:false),
      $this->parseComment(!empty($options['comment'])&#63;$options['comment']:''),
      $this->parseForce(!empty($options['force'])&#63;$options['force']:'')
    ),$sql);
  return $sql;
}

ログイン後にコピー

可以看到,在parseSql中用正则表达式拼接了sql语句,但并没有直接的去处理各种插叙你的数据格式,而是在解析变量的过程中调用了多个函数,此处拿parseWhere举例子。

protected function parseWhere($where) {
  $whereStr = '';
  if(is_string($where)) {   // 直接使用字符串条件
    $whereStr = $where;
  }
  else{            // 使用数组表达式
    /*设定逻辑规则,如or and xor等,默认为and,此处省略*/
    $operate=' AND ';
    /*解析特殊格式的表达式并且格式化输出*/
    foreach ($where as $key=>$val){
      if(0===strpos($key,'_')) {  // 解析特殊条件表达式
        $whereStr  .= $this->parseThinkWhere($key,$val);
      }
      else{            // 查询字段的安全过滤
        $multi = is_array($val) && isset($val['_multi']); //判断是否有复合查询
        $key  = trim($key);
        /*处理字段中包含的| &逻辑*/
        if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段
          /*将|换成or,并格式化输出,此处省略*/
        }
        elseif(strpos($key,'&')){
          /*将&换成and,并格式化输出,此处省略*/
        }
        else{
          $whereStr .= $this->parseWhereItem($this->parseKey($key),$val);
        }
      }
      $whereStr .= $operate;
    }
    $whereStr = substr($whereStr,0,-strlen($operate));
  }
  return empty($whereStr)&#63;'':' WHERE '.$whereStr;
}
// where子单元分析
protected function parseWhereItem($key,$val) {
  $whereStr = '';
  if(is_array($val)){
    if(is_string($val[0])){
      $exp  =  strtolower($val[0]);
      //如果是$map['id']=array('eq',100)一类的结构,那么解析成数据库可执行格式
      if(preg_match('/^(eq|neq|gt|egt|lt|elt)$/',$exp)){
        $whereStr .= $key.' '.$this->exp[$exp].' '.$this->parseValue($val[1]);
      }
      //如果是模糊查找格式
      elseif(preg_match('/^(notlike|like)$/',$exp)){// 模糊查找,$map['name']=array('like','thinkphp%');
        if(is_array($val[1])) { //解析格式如下:$map['b'] =array('notlike',array('%thinkphp%','%tp'),'AND');
          $likeLogic =  isset($val[2])&#63;strtoupper($val[2]):'OR';  //如果没有设定逻辑结构,则默认为OR
          if(in_array($likeLogic,array('AND','OR','XOR'))){
            /* 根据逻辑结构,组合语句,此处省略*/
            $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')';             
          }
        }
        else{
          $whereStr .= $key.' '.$this->exp[$exp].' '.$this->parseValue($val[1]);
        }
      }elseif('bind' == $exp ){ // 使用表达式,pdo数据绑定
        $whereStr .= $key.' = :'.$val[1];
      }elseif('exp' == $exp ){ // 使用表达式 $map['id'] = array('exp',' IN (1,3,8) ');
        $whereStr .= $key.' '.$val[1];
      }elseif(preg_match('/^(notin|not in|in)$/',$exp)){ //IN运算 $map['id'] = array('not in','1,5,8');
        if(isset($val[2]) && 'exp'==$val[2]){
          $whereStr .= $key.' '.$this->exp[$exp].' '.$val[1];
        }else{
          if(is_string($val[1])) {
             $val[1] = explode(',',$val[1]);
          }
          $zone   =  implode(',',$this->parseValue($val[1]));
          $whereStr .= $key.' '.$this->exp[$exp].' ('.$zone.')';
        }
      }elseif(preg_match('/^(notbetween|not between|between)$/',$exp)){ //BETWEEN运算
        $data = is_string($val[1])&#63; explode(',',$val[1]):$val[1];
        $whereStr .= $key.' '.$this->exp[$exp].' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]);
      }else{ //否则抛出异常
        E(L('_EXPRESS_ERROR_').':'.$val[0]);
      }
    }
    else{  //解析如:$map['status&score&title'] =array('1',array('gt','0'),'thinkphp','_multi'=>true);
      $count = count($val);
      $rule = isset($val[$count-1]) &#63; (is_array($val[$count-1]) &#63; strtoupper($val[$count-1][0]) : strtoupper($val[$count-1]) ) : '' ; 
      if(in_array($rule,array('AND','OR','XOR'))){
        $count = $count -1;
      }else{
        $rule  = 'AND';
      }
      for($i=0;$i<$count;$i++){
        $data = is_array($val[$i])&#63;$val[$i][1]:$val[$i];
        if('exp'==strtolower($val[$i][0])) {
          $whereStr .= $key.' '.$data.' '.$rule.' ';
        }else{
          $whereStr .= $this->parseWhereItem($key,$val[$i]).' '.$rule.' ';
        }
      }
      $whereStr = '( '.substr($whereStr,0,-4).' )';
    }
  }
  else {
    //对字符串类型字段采用模糊匹配
    $likeFields  =  $this->config['db_like_fields'];
    if($likeFields && preg_match('/^('.$likeFields.')$/i',$key)) {
      $whereStr .= $key.' LIKE '.$this->parseValue('%'.$val.'%');
    }else {
      $whereStr .= $key.' = '.$this->parseValue($val);
    }
  }
  return $whereStr;
}
protected function parseThinkWhere($key,$val) {   //解析特殊格式的条件
  $whereStr  = '';
  switch($key) {
    case '_string':$whereStr = $val;break;                 // 字符串模式查询条件
    case '_complex':$whereStr = substr($this->parseWhere($val),6);break;  // 复合查询条件
    case '_query':// 字符串模式查询条件
      /*处理逻辑结构,并且格式化输出字符串,此处省略*/
  }
  return '( '.$whereStr.' )';
}

ログイン後にコピー

上面的两个函数很长,我们再精简一些来看:parseWhere首先判断查询数据是不是字符串,如果是字符串,直接返回字符串,否则,遍历查询条件的数组,挨个解析。

由于TP支持_string,_complex之类的特殊查询,调用了parseThinkWhere来处理,对于普通查询,就调用了parseWhereItem。

在各自的处理过程中,都调用了parseValue,追踪一下,其实是用了addslashes来过滤,虽然addslashes在非utf-8编码的页面中会造成宽字节注入,但是如果页面和数据库均正确编码的话,还是没什么问题的。

您可能感兴趣的文章:

  • ThinkPHP php 框架学习笔记
  • PHP隐形一句话后门,和ThinkPHP框架加密码程序(base64_decode)
  • ThinkPHP框架实现session跨域问题的解决方法
  • 对于ThinkPHP框架早期版本的一个SQL注入漏洞详细分析
  • ThinkPHP框架任意代码执行漏洞的利用及其修复方法
  • ThinkPHP框架设计及扩展详解
  • ThinkPHP、ZF2、Yaf、Laravel框架路由大比拼
  • thinkphp3.2中Lite文件替换框架入口文件或应用入口文件的方法
  • 使用Thinkphp框架开发移动端接口
  • ThinkPHP开发框架函数详解:C方法

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1110081.htmlTechArticleThinkPHP框架安全实现分析,thinkphp框架实现 ThinkPHP框架是国内比较流行的PHP框架之一,虽然跟国外的那些个框架没法比,但优点在于,恩,中...
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++ での機械学習アルゴリズムの実装: セキュリティに関する考慮事項とベスト プラクティス C++ での機械学習アルゴリズムの実装: セキュリティに関する考慮事項とベスト プラクティス Jun 01, 2024 am 09:26 AM

C++ で機械学習アルゴリズムを実装する場合、データ プライバシー、モデルの改ざん、入力検証などのセキュリティを考慮することが重要です。ベスト プラクティスには、安全なライブラリの採用、権限の最小化、サンドボックスの使用、継続的な監視が含まれます。実際のケースでは、Botan ライブラリを使用して CNN モデルを暗号化および復号化し、安全なトレーニングと予測を確保する方法を示します。

Struts 2 フレームワークのセキュリティ構成と強化 Struts 2 フレームワークのセキュリティ構成と強化 May 31, 2024 pm 10:53 PM

Struts2 アプリケーションを保護するには、次のセキュリティ構成を使用できます。 未使用の機能を無効にする コンテンツ タイプ チェックを有効にする 入力を検証する セキュリティ トークンを有効にする CSRF 攻撃を防ぐ RBAC を使用してロールベースのアクセスを制限する

PHP マイクロフレームワーク: Slim と Phalcon のセキュリティに関する議論 PHP マイクロフレームワーク: Slim と Phalcon のセキュリティに関する議論 Jun 04, 2024 am 09:28 AM

PHP マイクロフレームワークにおける Slim と Phalcon のセキュリティ比較では、Phalcon には CSRF および XSS 保護、フォーム検証などのセキュリティ機能が組み込まれていますが、Slim にはすぐに使用できるセキュリティ機能がなく、手動で実装する必要があります。セキュリティ対策。セキュリティ クリティカルなアプリケーションの場合、Phalcon はより包括的な保護を提供するため、より良い選択肢となります。

Spring Boot フレームワークのセキュリティを強化する方法 Spring Boot フレームワークのセキュリティを強化する方法 Jun 01, 2024 am 09:29 AM

SpringBoot フレームワークのセキュリティを強化する方法 ユーザー データを保護し、攻撃を防ぐには、SpringBoot アプリケーションのセキュリティを強化することが重要です。 SpringBoot のセキュリティを強化するためのいくつかの重要な手順を次に示します。 1. HTTPS を有効にする HTTPS を使用してサーバーとクライアントの間に安全な接続を確立し、情報の盗聴や改ざんを防ぎます。 SpringBoot では、application.properties で次の設定を行うことで HTTPS を有効にできます:server.ssl.key-store=path/to/keystore.jksserver.ssl.k

Java フレームワークのセキュリティ アーキテクチャ設計は、ビジネス ニーズとどのようにバランスをとる必要がありますか? Java フレームワークのセキュリティ アーキテクチャ設計は、ビジネス ニーズとどのようにバランスをとる必要がありますか? Jun 04, 2024 pm 02:53 PM

Java フレームワーク設計では、セキュリティ ニーズとビジネス ニーズのバランスをとることでセキュリティを実現し、主要なビジネス ニーズを特定し、関連するセキュリティ要件に優先順位を付けます。柔軟なセキュリティ戦略を策定し、脅威に階層的に対応し、定期的に調整します。アーキテクチャの柔軟性を考慮し、ビジネスの進化をサポートし、抽象的なセキュリティ機能を考慮します。効率と可用性を優先し、セキュリティ対策を最適化し、可視性を向上させます。

SHIBコインにとってより安全なウォレットはどれですか? (初心者の方は必ずお読みください) SHIBコインにとってより安全なウォレットはどれですか? (初心者の方は必ずお読みください) Jun 05, 2024 pm 01:30 PM

SHIBコインは、投資家にとってもはや馴染みのないものではありませんが、市場の発展に伴い、SHIBの現在の市場価値は12位にランクされており、数え切れないほどの投資を集めていることがわかります。 . 投資家が投資に参加します。過去に、市場では頻繁に取引やウォレットのセキュリティに関するインシデントが発生しており、多くの投資家は、現時点でどのウォレットがSHIBコインを保管するのが安全なのか疑問に思っています。市場データの分析によると、比較的安全なウォレットは主に OKXWeb3Wallet、imToken、MetaMask ウォレットです。次に、これらについて編集者が詳しく説明します。 SHIBコインにとってより安全なウォレットはどれですか?現在、SHIBコインはOKXWeに置かれています

ThinkPHP6およびElasticSearch-PHPクライアントを使用してElasticSearch 8に接続するときのCurlエラー77の問題を解決する方法? ThinkPHP6およびElasticSearch-PHPクライアントを使用してElasticSearch 8に接続するときのCurlエラー77の問題を解決する方法? Mar 31, 2025 pm 11:36 PM

Elasticsearch-PHPクライアントと組み合わせてElasticsearchを操作するThinkPhp6フレームワークを使用して...

ThinkPhp6ルーティング:中国語などの特殊文字を含むURLパラメーターを完全に取得する方法は? ThinkPhp6ルーティング:中国語などの特殊文字を含むURLパラメーターを完全に取得する方法は? Apr 01, 2025 pm 02:51 PM

ThinkPhp6ルーティングパラメーターは、中国と完全な買収で処理されます。 ThinkPhp6フレームワークでは、特殊文字(中国語や句読点など)を含むURLパラメーターがしばしば処理されます...

See all articles