您好,登錄后才能下訂單哦!
作為一個在X94的航空工程師,你的老板要求你從2號樓的工程圖中檢索出一個特定的專利。不幸的是,進入大樓需要你出示你具有進入大樓的資格的證明,然后你迅速地以徽章的形式出示給了保安。到了十三樓,進入建筑師工程師圖紙庫要求通過他們的生物鑒定系統(tǒng)來驗證你是你聲稱的那個人。最后在你的目的地,你提供給庫管理員一串對你毫無意義的字母數(shù)字代碼,但是在合適的人手上,它可以轉(zhuǎn)換成哪里可以找的你需要的工程圖的真實索引。
在上面的比喻中,我們可以很容易地確定適當(dāng)?shù)陌踩胧﹣肀Wo敏感數(shù)據(jù)的訪問。除了個人訪問所需驗證,一個附加的可能不是很明顯的安全措施就是以字母數(shù)字碼的形式混淆技術(shù)文檔身份,并間接映射到真實的文檔身份和庫中的位置。
形象地說,這個比喻是一流行的被稱為“非安全的直接對象引用”的Web應(yīng)用安全漏洞的解答,該漏洞在OWASP最關(guān)鍵漏洞Top10中排第四。但如果這就是答案的話, 你接下來自然會問“關(guān)于我Web應(yīng)用的具體問題是什么且該如何去解決?”
我們對在我們網(wǎng)站上展示商品的想法都很熟悉。用戶通過發(fā)起請求來查看商品詳情,向他們的購物車里添加商品,或進行類似的活動。你很有可能會利用商品的ID去標(biāo)識用戶正在請求哪件商品的詳細信息,標(biāo)識添加進他們購物車的商品等等。最重要的是,這個ID很有可能是存儲商品信息的數(shù)據(jù)庫表的主鍵。如果真是這樣,那么我們就擁有了一個直接對象引用。在網(wǎng)頁上展示的某個商品(對象)被特定的ID標(biāo)識,而這個ID是對數(shù)據(jù)庫中相同標(biāo)識的直接引用。
“說的不錯,但那又如何?”是這樣,在簡單的商家對顧客場景下,上文所講的情況不是什么問題。但假定這是一個金融類服務(wù)應(yīng)用,比方說是你最常用的網(wǎng)上銀行,上面有你的各個活期、定期儲蓄賬戶和其他敏感數(shù)據(jù),那將會怎樣呢?想象一下,你在你的賬戶頁面選擇查看 ID 為 1344573490 的存款賬戶的詳細信息:
作為一個經(jīng)過身份核實的名為Mary Wiggins的用戶,網(wǎng)站顯示了針對你存款賬戶的信息:
我們可以直接看出這個支票戶頭就是我們擁有的賬戶,同時也能確認這是一個直接引用。但要是你決定把 accountNumber 參數(shù)從 1344573490 改為 1344573491,那將會發(fā)生什么呢?
Erin Maley,誰是Erin Maley?那不是我們。我們作為Mary Wiggins是已經(jīng)明確被認證過的。我們所有所做的事情就是順序地增加賬戶號直到下一個可能的值,并且我們可以看到一個不是我們所持有的賬戶信息。在這個例子中,我們有一個直接關(guān)聯(lián)的賬戶,它可以被定義為系統(tǒng)內(nèi)任何地方被標(biāo)識的賬戶號。更進一步說,我們演習(xí)了一個潛在的問題,曝光一個直接相關(guān)的賬戶是簡單的數(shù)據(jù)工程。
如果你自己覺得這不是直接引用惹的禍,而是身份驗證上出了差錯,那么你只對了一半。我們討論不安全直接對象引用所造成的缺陷時,實際上看到了兩個問題。我發(fā)現(xiàn)下圖能夠更清楚的描述這個缺陷究竟是什么:
如果不安全的直接對象引用涉及以下兩方面……
泄露敏感數(shù)據(jù)
缺乏合理的訪問控制
……那么我們對于彌補這個缺陷的看法是什么,以及我們應(yīng)該何時采取行動?接下來,我們首先解決影響最大范圍最廣的問題——合理的訪問控制。
就像文章開頭舉的例子,多層級的訪問控制是必須的。雖然我們有權(quán)進入大樓,但進入樓內(nèi)某些區(qū)域需要特定的權(quán)限。當(dāng)我們考慮在Web應(yīng)用中保護資源時,可以使用這樣的準(zhǔn)則來達到目的。
首先,當(dāng)前合法用戶是否有權(quán)請求資源?在我們對該用戶一無所知的情況下,該如何確定當(dāng)前用戶可以被允許發(fā)起這個請求?因此第一步我們要做的是,在和用戶交互時,通過添加訪問控制來保護資源。
在ASP.NET中,用戶交互通過控制器動作(controller action)完成。我們可以在ASP.NET MVC控制器上使用[Authorize]特性(attribute)來確保用戶只有先經(jīng)過系統(tǒng)核實身份才能執(zhí)行控制器上的動作,而匿名用戶將被拒絕。
[Authorize] public class AccountsController : Controller { [HttpGet] public ActionResult Details(long accountNumber) { //...
這樣就確保了API無法被公開使用,根據(jù)你的ASP.NET配置,用戶會被重定向到登錄頁面(默認行為)。[Authorize]特性通過額外的約束來匹配特定的用戶和角色:
[Authorize(Roles = "Admin, Manager")] public class AccountsController : Controller { //..
[Authorize]特性除了可以被應(yīng)用到控制器動作上外,還能進行更多粒度的控制。例如在控制器上放置身份驗證約束,同時在控制器的不同動作上使用基于角色的訪問控制。
在我們的銀行賬戶例子中,只對用戶進行身份驗證是不夠的,因為我們(只經(jīng)過身份驗證的用戶)竟然能訪問另一個用戶的支票賬戶信息。對于像銀行賬戶例子中看到的這種濫用行為,通常被稱作為橫向權(quán)限提升,用戶可以訪問其他相同等級的用戶信息。然而,有權(quán)發(fā)起對某個資源的請求與擁有對實際資源的權(quán)限是完全不同的概念。
因此,我們必須采取的第二層也是最重要訪問控制就是,保證用戶被授權(quán)訪問資源。在基于角色的訪問控制的情況下,這就跟確保用戶屬于合理的角色一樣容易。如果被請求的資源只需要某個提升的權(quán)限,你可以利用之前演示的[Authorize]的Role屬性來搞定。
[Authorize(Roles = "Admin")] public class AccountsController : Controller { //..
但是更多的時候,你被要求在數(shù)據(jù)層面對用戶進行權(quán)限驗證,以保證其有權(quán)訪問所請求的資源??紤]到受許多不同因素的影響,解決方案多種多樣,就上文提到的查看銀行賬戶詳情的案例,我們可以驗證用戶是否為其所請求賬戶的擁有者:
[Authorize] public class AccountsController : Controller { [HttpGet] public ActionResult Details(long accountNumber) { Account account = _accountRepository.Find(accountNumber); if (account.UserId != User.Identity.GetUserId()) { return new HttpUnauthorizedResult("User is not Authorized."); } //...
記得我們已經(jīng)在控制器級別使用了[Authorize]特性,所以沒必要在動作級別畫蛇添足。
需要重點注意的是,在上面的關(guān)于在ASP.NET中使用Forms Authentication引發(fā)的非授權(quán)結(jié)果的例子中將會強制一個302跳轉(zhuǎn)到登陸頁面,無論用戶是否已經(jīng)的到授權(quán)。因此,你或許需要對處理這種行為作出必要的改變,這取決于你的應(yīng)用,你的需求和你用戶的期望。你的選擇或者你是否需要處理這種行為很大程度上依賴于框架的風(fēng)格,使用OWIN模塊,和你的應(yīng)用的需要。
好處是減少了去確定沒有用戶提權(quán)的次數(shù),保證了合適的訪問權(quán)限控制。至少,我們可以加強對請求本身和請求對被請求資源的訪問的訪問控制。但是,如同我前面提到的若干種場合, 在我們的應(yīng)用加強防止數(shù)據(jù)泄露總是應(yīng)該評估的一個安全步驟。什么是我所說的“數(shù)據(jù)泄露”?我們可以通過研究其他包含不安全的直接對象引用(如混淆)來回答這個問題。
混淆 就是故意隱藏意圖的行為。在我們這兒, 我們可以使用混淆手段來推斷安全性。 一個人們認同的簡單例子就是URL短鏈。雖然初衷并不是為了安全性, 像這樣的URL http://bit.ly/1Gg2Pnn 是從真實的URL從混淆過來的。 根據(jù)這個短鏈, Bit.ly能夠?qū)⒒煜腢RL http://bit.ly/1Gg2Pnn 映射到真正的http://lockmedown.com/preventing-xss-in-asp-net-made-easy.
我使用了關(guān)于銀行賬戶交互的金融例子,因為這是一個完美的例子,在其中的元數(shù)據(jù)是很敏感的。在這種情況下,一個支票帳戶就是我們要保護的數(shù)據(jù)。而賬戶號碼就是關(guān)于支票賬號的元數(shù)據(jù),我們認為這是敏感數(shù)據(jù)。
我們看到在前面我們只是增加了帳號的數(shù)值就能夠嚴格訪問另一個用戶的支票帳戶,因為沒有數(shù)據(jù)級訪問控制。但我們可以通過混淆賬號建立另一防御屏障使惡意用戶失去直接駕馭系統(tǒng)的能力,這通過改變數(shù)值就行。
可以實現(xiàn)不同級別的混淆,每一級別都能提供不同級別的安全性和平衡性.我們將看到第一個選項是一種比較常見的,安全的但有些限制的選項,我喜歡稱之為“視野”,該詞間接參考地圖。
引用映射與 Bit.ly 短網(wǎng)址并沒有什么不同,你的服務(wù)器知道怎樣將一個公開的表面值映射到一個內(nèi)部值來代表敏感數(shù)據(jù)。作用域代表我們用于限制映射使用而放入的限制條件。這對理論研究已經(jīng)足夠了,我們來看一個例子:
我們認為一個賬號編號例如1344573490是一個敏感數(shù)據(jù),我們希望隱藏它并只提供可被確認的賬號持有者。為了避免暴露賬號編號,我們可以提供一個間接引用到賬號編號的公開表面值。服務(wù)器將會知道怎樣把這個間接引用映射回直接引用,這個直接引用指向我們的賬號編號。服務(wù)器使用的映射存儲在一個 ASP.NET 用戶回話中,這就是作用域,關(guān)于作用域的更多內(nèi)容,來看看這個實現(xiàn):
public static class ScopedReferenceMap
{
private const int Buffer = 32;
/// <summary>
/// Extension method to retrieve a public facing indirect value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static string GetIndirectReference<T>(this T value)
{
//Get a converter to convert value to string
var converter = TypeDescriptor.GetConverter(typeof (T));
if (!converter.CanConvertTo(typeof (string)))
{
throw new ApplicationException("Can't convert value to string");
}
var directReference = converter.ConvertToString(value);
return CreateOrAddMapping(directReference);
}
/// <summary>
/// Extension method to retrieve the direct value from the user session
/// if it doesn't exists, the session has ended or this is possibly an attack
/// </summary>
/// <param name="indirectReference"></param>
/// <returns></returns>
public static string GetDirectReference(this string indirectReference)
{
var map = HttpContext.Current.Session["RefMap"];
if (map == null ) throw new ApplicationException("Can't retrieve direct reference map");
return ((Dictionary<string, string>) map)[indirectReference];
}
private static string CreateOrAddMapping(string directReference)
{
var indirectReference = GetUrlSaveValue();
var map =
(Dictionary<string, string>) HttpContext.Current.Session["RefMap"] ??
new Dictionary<string, string>();
//If we have it, return it.
if (map.ContainsKey(directReference)) return map[directReference];
map.Add(directReference, indirectReference);
map.Add(indirectReference, directReference);
HttpContext.Current.Session["RefMap"] = map;
return indirectReference;
}
private static string GetUrlSaveValue()
{
var csprng = new RNGCryptoServiceProvider();
var buffer = new Byte[Buffer];
//generate the random indirect value
csprng.GetBytes(buffer);
//base64 encode the random indirect value to a URL safe transmittable value
return HttpServerUtility.UrlTokenEncode(buffer);
}
}
這里,我們創(chuàng)建了一個簡單的工具類 ScopedReferenceMap,可以提供擴展的方法處理一個值例如我們的銀行卡號1344573490處理成 Xvqw2JEm84w1qqLN1vE5XZUdc7BFqarB0,這就是所謂的間接引用。
最終,當(dāng)一個間接引用值被請求時,我們使用一個用戶會話來作為保持請求中的間接引用和直接引用之間的映射的一種方法。用戶會話成為間接引用的作用域,而且強制在每個用戶映射上加上時間限制。只有經(jīng)過驗證和指定的用戶會話才具有檢索的能力。
你可以利用它在任何你需要的地方創(chuàng)建間接引用,例如:
AccountNumber = accountNumber.GetIndirectReference(); //create an indirect reference
現(xiàn)在,在一個使用如下URL的傳入請求(請求一個賬號的詳細信息):
我們可以看出,對accountNumber的間接引用映射通過與我們的訪問控制合作重新得到真實值:
[HttpGet] public ActionResult Details(string accountNumber) { //get direct reference var directRefstr = accountNumber.GetDirectReference(); var accountNum = Convert.ToInt64(directRefstr); Account account = _accountRepository.Find(accountNum); //Verify authorization if (account.UserId != User.Identity.GetUserId()) { return new HttpUnauthorizedResult("User is not Authorized."); } //…
在我們對獲得直接引用的嘗試中,如果ASP.NET用戶會話沒有獲得一個映射,那就可能是受到了***。但是,如果映射存在,仍然得到了直接引用,則可能是值被篡改了。
正如我前面提到的,用戶會話創(chuàng)建了一個作用域,用戶和時間約束限制了映射回直接引用的能力。這些限制條件以其自身的形式提供額外的安全措施。但是,你或許在使用 ASP.NET 會話狀態(tài)時遇到問題,這可能是由于已知的安全弱點,你也可能會問怎樣才能讓這些限制條件與提供含狀態(tài)傳輸(Representational State Transfer)風(fēng)格的引擎例如超媒體狀態(tài)應(yīng)用引擎良好的合作共處?真是個好問題,讓我們來檢查一些替代選項吧。
HATEOAS Gonna Hate
如果你思考過通過網(wǎng)絡(luò)服務(wù)進行的典型交互方式,這種在你的應(yīng)用中通過發(fā)送一個 request 和接受一個包含額外超媒體鏈接(例如 URLs)的 response 來獲得額外的資源的方式對 web 開發(fā)者來說是一個可以理解的概念。
這個概念經(jīng)過高度的精煉已經(jīng)成為構(gòu)建 REST 風(fēng)格的網(wǎng)絡(luò)服務(wù)的支柱之一:超媒體作為應(yīng)用程序狀態(tài)或 HATEOAS 的引擎。用一句話來解釋 HATEOAS 是網(wǎng)絡(luò)服務(wù)提供對于資源發(fā)現(xiàn)操作的能力:它通過在 HTTP 響應(yīng)中提供超媒體鏈接。這不是一篇關(guān)于定義 REST 風(fēng)格網(wǎng)絡(luò)服務(wù)的論文,所以,如果 REST 和 HATEOAS 對你來說是陌生概念,你需要查看關(guān)于 REST 和關(guān)于 HATEOAS 的資料來對他們有一個了解。
因此,提供包含有作用域的間接引用參數(shù)的 URL 的想法與像 HATEOAS 這樣的概念或需要一直提供持久性 URL (具有較長生存時間的 URL )之間是有很大困難的。如果我們希望提供持久性 URL 的同時,包含間接引用值,那么我們就需要采用一種不同的安全方法,我們應(yīng)該怎么做呢?
靜態(tài)間接引用映射
為了提供包含間接引用的持久性 URL,我們接下來就需要一些方法來在任意給定的時間或者至少是在未來相當(dāng)長的一段時間內(nèi)將間接值映射回原始的直接值。如果我們想要持久性,那么像使用一個用戶會話來維持一個引用映射這樣的限制條件將不再是個可用的選項。讓我們來看看可以使用靜態(tài)間接引用映射方案的場景。
假設(shè)你有一個 B2B 網(wǎng)絡(luò)應(yīng)用,它允許商家獲得指定給他們的 VIP 商品的定價。給客戶系統(tǒng)發(fā)送一個請求,返回一個包含鏈接到此客戶的 VIP 商品的附加超媒體鏈接的響應(yīng)。當(dāng)點擊 VIP 商品鏈接時,接收到的響應(yīng)就包含他們指定商家的所有可用 VIP 商品的超媒體鏈接。
在我們的例子中,我們決定通過創(chuàng)建一個間接引用,對VIP商品URL中的VIP商品ID加以混淆,到時候我們能很快地重新映射回商品的實際ID。
例子: https://AppCore.com/business/Acme/VIP/Products/99933
針對我們的處境,加密是一個不錯的選擇,這使得我們能更好的掌控將間接引用映射回實際商品ID的生命周期。
如同我們在域引用例子中做的那樣,利用相同的API,來看看它將會成為什么樣子,然后我們帶著關(guān)注和額外的選擇,再討論一下我們做了什么和為什么用這種方法:
public static class StaticReferenceMap
{
public const int KeySize = 128; //bits
public const int IvSize = 16; //bytes
public const int OutputByteSize = KeySize / 8;
private static readonly byte[] Key;
static StaticReferenceMap()
{
Key = //pull 128 bit key in
}
/// <summary>
/// Generates an encrypted value using symmetric encryption.
/// This is utilizing speed over strength due to the limit of security through obscurity
/// </summary>
/// <typeparam name="T">Primitive types only</typeparam>
/// <param name="value">direct value to be encrypted</param>
/// <returns>Encrypted value</returns>
public static string GetIndirectReferenceMap<T>(this T value)
{
//Get a converter to convert value to string
var converter = TypeDescriptor.GetConverter(typeof (T));
if (!converter.CanConvertTo(typeof (string)))
{
throw new ApplicationException("Can't convert value to string");
}
//Convert value direct value to string
var directReferenceStr = converter.ConvertToString(value);
//encode using UT8
var directReferenceByteArray = Encoding.UTF8.GetBytes(directReferenceStr);
//Encrypt and return URL safe Token string which is the indirect reference value
var urlSafeToken = EncryptDirectReferenceValue<T>(directReferenceByteArray);
return urlSafeToken;
}
/// <summary>
/// Give a encrypted indirect value, will decrypt the value and
/// return the direct reference value
/// </summary>
/// <param name="indirectReference">encrypted string</param>
/// <returns>direct value</returns>
public static string GetDirectReferenceMap(this string indirectReference)
{
var indirectReferenceByteArray =
HttpServerUtility.UrlTokenDecode(indirectReference);
return DecryptIndirectReferenceValue(indirectReferenceByteArray);
}
private static string EncryptDirectReferenceValue<T>(byte[] directReferenceByteArray)
{
//IV needs to be a 16 byte cryptographic stength random value
var iv = GetRandomValue();
//We will store both the encrypted value and the IV used - IV is not a secret
var indirectReferenceByteArray = new byte[OutputByteSize + IvSize];
using (SymmetricAlgorithm algorithm = GetAlgorithm())
{
var encryptedByteArray =
GetEncrptedByteArray(algorithm, iv, directReferenceByteArray);
Buffer.BlockCopy(
encryptedByteArray, 0, indirectReferenceByteArray, 0, OutputByteSize);
Buffer.BlockCopy(iv, 0, indirectReferenceByteArray, OutputByteSize, IvSize);
}
return HttpServerUtility.UrlTokenEncode(indirectReferenceByteArray);
}
private static string DecryptIndirectReferenceValue(
byte[] indirectReferenceByteArray)
{
byte[] decryptedByteArray;
using (SymmetricAlgorithm algorithm = GetAlgorithm())
{
var encryptedByteArray = new byte[OutputByteSize];
var iv = new byte[IvSize];
//separate off the actual encrypted value and the IV from the byte array
Buffer.BlockCopy(
indirectReferenceByteArray,
0,
encryptedByteArray,
0,
OutputByteSize);
Buffer.BlockCopy(
indirectReferenceByteArray,
encryptedByteArray.Length,
iv,
0,
IvSize);
//decrypt the byte array using the IV that was stored with the value
decryptedByteArray = GetDecryptedByteArray(algorithm, iv, encryptedByteArray);
}
//decode the UTF8 encoded byte array
return Encoding.UTF8.GetString(decryptedByteArray);
}
private static byte[] GetDecryptedByteArray(
SymmetricAlgorithm algorithm, byte[] iv, byte[] valueToBeDecrypted)
{
var decryptor = algorithm.CreateDecryptor(Key, iv);
return decryptor.TransformFinalBlock(
valueToBeDecrypted, 0, valueToBeDecrypted.Length);
}
private static byte[] GetEncrptedByteArray(
SymmetricAlgorithm algorithm, byte[] iv, byte[] valueToBeEncrypted)
{
var encryptor = algorithm.CreateEncryptor(Key, iv);
return encryptor.TransformFinalBlock(
valueToBeEncrypted, 0, valueToBeEncrypted.Length);
}
private static AesManaged GetAlgorithm()
{
var aesManaged = new AesManaged
{
KeySize = KeySize,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
return aesManaged;
}
private static byte[] GetRandomValue()
{
var csprng = new RNGCryptoServiceProvider();
var buffer = new Byte[16];
//generate the random indirect value
csprng.GetBytes(buffer);
return buffer;
}
}
在這里,我們的API應(yīng)該看起來像ScopedReferenceMap,只有在發(fā)生變化時才會在內(nèi)部運行,我們借助了.NET 中具有128位秘鑰的AesManaged對稱加密庫和一個對初始向量(IV)高度加密的隨機值。你們中的一些人可能會意識到,怎樣才能做到在速度與強度之間的最優(yōu)化呢?
AesManaged在實例中要比FIPS快約170倍,相當(dāng)于AesCryptoServiceProvider
128位長度需要執(zhí)行算法的次數(shù)少于4次,這要比更大的256位長度要小
關(guān)鍵點之一是我們?yōu)槌跏枷蛄浚↖V)生成一個強加密的隨機值,這個隨機值應(yīng)用到了所有的加密過程中。秘鑰同樣是個機密,為了保密,我選擇將它留給你,讓你來找出你想怎樣使用秘鑰,好的一方面是我們不必與任何人分享秘鑰。最終,我們存儲帶有密碼的非機密的初始向量(間接引用),這樣我們就可以在一個請求中解密間接引用。
要絕對地清楚,這不是一個可替代的訪問控制。這只能用或應(yīng)該用在正確的訪問控制連接上。
現(xiàn)在,也還有一個沒有那么復(fù)雜的方法。一種改進過的方法是包含了上述過程的加密認證(AE),但是這是一個基于哈希消息驗證碼的過程。認證加密也支持像填充、消息篡改等暴漏的安全***。此外,像 Stan Drapkin那樣的學(xué)著會告訴你對稱加密必須被認證加密。
然而,這并不是一篇關(guān)于加密的文章。所有的出發(fā)點就是以最后一個選項來“照亮”其他的選項,目的是給那些不間接使用作用域的用戶會話,如.NET,提供一個敏感數(shù)據(jù)的模糊環(huán)境。
緩解和減少不安全的直接對象引用的唯一可靠的方法是具有適當(dāng)?shù)脑L問控制,再多的混淆都不能阻止對數(shù)據(jù)的未授權(quán)訪問。
資料是非常重要的,惡意用戶會以對他們有利的方式來使用它,當(dāng)你意識到的時候就太晚了。因此,當(dāng)你認為一項數(shù)據(jù)是個敏感數(shù)據(jù)時,你需要應(yīng)用一定等級的混淆來進行技術(shù)上的限制,例如使用用戶會話。但是會有一個.NET會話開銷,所以要知道你應(yīng)該怎樣利用它。
絕大多數(shù)應(yīng)用并不需要混淆和創(chuàng)建間接引用,但是對于像金融等高度敏感的網(wǎng)站最好加上這層額外的安全層。
最后一點是:對特定數(shù)據(jù)值的混淆只是一個模糊的安全。它需要與其它安全措施同時使用,例如正確的訪問控制。從這方面來說,不應(yīng)該單獨依賴它。
不安全的直接對象引用主要涉及的內(nèi)容是,通過合理的訪問控制來保護數(shù)據(jù)不被未經(jīng)授權(quán)的訪問。其次,為了防止像直接引用鍵值那樣的敏感數(shù)據(jù)遭到泄露,要了解如何以及何時該通過間接引用那些鍵值來添加一層混淆。最后,在決定要使用混淆技術(shù)時,要意識到利用間接引用映射來彌補漏洞的局限性。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。