mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Issue 2447 – Do not allow WebDAV redirects to other hosts by default + Issue 2448 – Do not allow WebDAV redirects to an unencrypted URL by default
https://winscp.net/tracker/2447 https://winscp.net/tracker/2448 Source commit: c777084ca5737c4283f256eb8cdf5c2fec5902af
This commit is contained in:
@@ -57,7 +57,7 @@ void THttp::SendRequest(const char * Method, const UnicodeString & Request)
|
||||
}
|
||||
}
|
||||
|
||||
FHostName = StrFromNeon(Uri.host);
|
||||
FHostName = Uri.GetHost();
|
||||
|
||||
UnicodeString UriPath = StrFromNeon(Uri.path);
|
||||
if (Uri.query != NULL)
|
||||
|
||||
@@ -50,6 +50,11 @@ bool TNeonUri::IsTls() const
|
||||
return SameText(StrFromNeon(scheme), HttpsProtocol);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString TNeonUri::GetHost() const
|
||||
{
|
||||
return StrFromNeon(host);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
struct TProxyAuthData
|
||||
{
|
||||
UnicodeString UserName;
|
||||
|
||||
@@ -34,6 +34,7 @@ struct TNeonUri : public ne_uri
|
||||
TNeonUri(const UnicodeString & Url);
|
||||
~TNeonUri();
|
||||
bool IsTls() const;
|
||||
UnicodeString GetHost() const;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
ne_session * CreateNeonSession(const TNeonUri & Uri);
|
||||
|
||||
@@ -224,6 +224,8 @@ void __fastcall TSessionData::DefaultSettings()
|
||||
|
||||
WebDavLiberalEscaping = false;
|
||||
WebDavAuthLegacy = false;
|
||||
WebDavCrossDomainRedirects = false;
|
||||
WebDavUnencryptedRedirects = false;
|
||||
|
||||
DefaultProxy();
|
||||
ProxyTelnetCommand = L"connect %host %port\\n";
|
||||
@@ -536,6 +538,8 @@ void __fastcall TSessionData::NonPersistent()
|
||||
\
|
||||
PROPERTY(WebDavLiberalEscaping); \
|
||||
PROPERTY(WebDavAuthLegacy); \
|
||||
PROPERTY(WebDavCrossDomainRedirects); \
|
||||
PROPERTY(WebDavUnencryptedRedirects); \
|
||||
\
|
||||
PROPERTY(PuttySettings); \
|
||||
\
|
||||
@@ -964,6 +968,12 @@ void TSessionData::DoLoad(
|
||||
|
||||
WebDavLiberalEscaping = Storage->ReadBool(L"WebDavLiberalEscaping", WebDavLiberalEscaping);
|
||||
WebDavAuthLegacy = Storage->ReadBool(L"WebDavAuthLegacy", WebDavAuthLegacy);
|
||||
if (!Unsafe)
|
||||
{
|
||||
LOADING_UNSAFE;
|
||||
WebDavCrossDomainRedirects = Storage->ReadBool(L"WebDavCrossDomainRedirects", WebDavCrossDomainRedirects);
|
||||
WebDavUnencryptedRedirects = Storage->ReadBool(L"WebDavUnencryptedRedirects", WebDavUnencryptedRedirects);
|
||||
}
|
||||
|
||||
IsWorkspace = Storage->ReadBool(L"IsWorkspace", IsWorkspace);
|
||||
Link = Storage->ReadString(L"Link", Link);
|
||||
@@ -1275,6 +1285,8 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
|
||||
|
||||
WRITE_DATA(Bool, WebDavLiberalEscaping);
|
||||
WRITE_DATA(Bool, WebDavAuthLegacy);
|
||||
WRITE_DATA(Bool, WebDavCrossDomainRedirects);
|
||||
WRITE_DATA(Bool, WebDavUnencryptedRedirects);
|
||||
|
||||
WRITE_DATA(Bool, IsWorkspace);
|
||||
WRITE_DATA(String, Link);
|
||||
@@ -4699,6 +4711,16 @@ void __fastcall TSessionData::SetWebDavAuthLegacy(bool value)
|
||||
SET_SESSION_PROPERTY(WebDavAuthLegacy);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void TSessionData::SetWebDavCrossDomainRedirects(bool value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(WebDavCrossDomainRedirects);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void TSessionData::SetWebDavUnencryptedRedirects(bool value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(WebDavUnencryptedRedirects);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
UnicodeString __fastcall TSessionData::GetInfoTip()
|
||||
{
|
||||
if (UsesSsh)
|
||||
|
||||
@@ -259,6 +259,8 @@ private:
|
||||
RawByteString FEncryptKey;
|
||||
bool FWebDavLiberalEscaping;
|
||||
bool FWebDavAuthLegacy;
|
||||
bool FWebDavCrossDomainRedirects;
|
||||
bool FWebDavUnencryptedRedirects;
|
||||
|
||||
UnicodeString FOrigHostName;
|
||||
int FOrigPortNumber;
|
||||
@@ -457,6 +459,8 @@ private:
|
||||
void __fastcall SetEncryptKey(UnicodeString value);
|
||||
void __fastcall SetWebDavLiberalEscaping(bool value);
|
||||
void __fastcall SetWebDavAuthLegacy(bool value);
|
||||
void SetWebDavCrossDomainRedirects(bool value);
|
||||
void SetWebDavUnencryptedRedirects(bool value);
|
||||
|
||||
TDateTime __fastcall GetTimeoutDT();
|
||||
void __fastcall SavePasswords(THierarchicalStorage * Storage, bool PuttyExport, bool DoNotEncryptPasswords, bool SaveAll);
|
||||
@@ -750,6 +754,8 @@ public:
|
||||
__property UnicodeString EncryptKey = { read = GetEncryptKey, write = SetEncryptKey };
|
||||
__property bool WebDavLiberalEscaping = { read = FWebDavLiberalEscaping, write = SetWebDavLiberalEscaping };
|
||||
__property bool WebDavAuthLegacy = { read = FWebDavAuthLegacy, write = SetWebDavAuthLegacy };
|
||||
__property bool WebDavCrossDomainRedirects = { read = FWebDavCrossDomainRedirects, write = SetWebDavCrossDomainRedirects };
|
||||
__property bool WebDavUnencryptedRedirects = { read = FWebDavUnencryptedRedirects, write = SetWebDavUnencryptedRedirects };
|
||||
|
||||
__property UnicodeString StorageKey = { read = GetStorageKey };
|
||||
__property UnicodeString SiteKey = { read = GetSiteKey };
|
||||
|
||||
@@ -1396,7 +1396,18 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
|
||||
FtpsOn = (Data->Ftps != ftpsNone);
|
||||
ADF(L"HTTPS: %s [Client certificate: %s]",
|
||||
(BooleanToEngStr(FtpsOn), LogSensitive(Data->TlsCertificateFile)));
|
||||
ADF(L"WebDAV: Tolerate non-encoded: %s", (BooleanToEngStr(Data->WebDavLiberalEscaping)));
|
||||
if (Data->WebDavLiberalEscaping)
|
||||
{
|
||||
ADF(L"WebDAV: Tolerate non-encoded: %s", (BooleanToEngStr(Data->WebDavLiberalEscaping)));
|
||||
}
|
||||
if (Data->WebDavCrossDomainRedirects)
|
||||
{
|
||||
ADF(L"WebDAV: Cross-domain redirects: %s", (BooleanToEngStr(Data->WebDavCrossDomainRedirects)));
|
||||
}
|
||||
if (Data->WebDavUnencryptedRedirects)
|
||||
{
|
||||
ADF(L"WebDAV: Unencrypted redirects: %s", (BooleanToEngStr(Data->WebDavUnencryptedRedirects)));
|
||||
}
|
||||
}
|
||||
if (Data->FSProtocol == fsS3)
|
||||
{
|
||||
|
||||
@@ -271,11 +271,6 @@ void TWebDAVFileSystem::NeonClientOpenSessionInternal(UnicodeString & CorrectedU
|
||||
bool Ssl = IsTlsSession(FSessionContext->NeonSession);
|
||||
FSessionInfo.SecurityProtocolName = Ssl ? LoadStr(FTPS_IMPLICIT) : EmptyStr;
|
||||
|
||||
if (Ssl != (FTerminal->SessionData->Ftps != ftpsNone))
|
||||
{
|
||||
FTerminal->LogEvent(FORMAT(L"Warning: %s", (LoadStr(UNENCRYPTED_REDIRECT))));
|
||||
}
|
||||
|
||||
{
|
||||
CorrectedUrl = EmptyStr;
|
||||
TAutoFlag Flag(FInitialHandshake);
|
||||
@@ -327,7 +322,7 @@ TWebDAVFileSystem::TSessionContext * TWebDAVFileSystem::NeonOpen(const UnicodeSt
|
||||
|
||||
std::unique_ptr<TSessionContext> Result(new TSessionContext());
|
||||
Result->FileSystem = this;
|
||||
Result->HostName = StrFromNeon(Uri.host);
|
||||
Result->HostName = Uri.GetHost();
|
||||
Result->PortNumber = Uri.port;
|
||||
Result->NtlmAuthenticationFailed = false;
|
||||
|
||||
@@ -395,6 +390,37 @@ UnicodeString __fastcall TWebDAVFileSystem::GetRedirectUrl()
|
||||
{
|
||||
UnicodeString Result = GetNeonRedirectUrl(FSessionContext->NeonSession);
|
||||
FTerminal->LogEvent(FORMAT(L"Redirected to \"%s\".", (Result)));
|
||||
|
||||
TNeonUri RedirectUri(Result);
|
||||
|
||||
if ((FTerminal->SessionData->Ftps != ftpsNone) && !RedirectUri.IsTls())
|
||||
{
|
||||
UnicodeString Message = LoadStr(UNENCRYPTED_REDIRECT);
|
||||
if (FTerminal->SessionData->WebDavUnencryptedRedirects)
|
||||
{
|
||||
FTerminal->LogEvent(FORMAT(L"Warning: %s", (Message)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(Message);
|
||||
}
|
||||
}
|
||||
|
||||
int PortNumber = static_cast<int>(RedirectUri.port);
|
||||
if (!SameText(RedirectUri.GetHost(), FSessionContext->HostName) ||
|
||||
(PortNumber != FSessionContext->PortNumber))
|
||||
{
|
||||
UnicodeString OtherHost = RedirectUri.GetHost();
|
||||
if (RedirectUri.port != ne_uri_defaultport(RedirectUri.scheme))
|
||||
{
|
||||
OtherHost = FORMAT(L"%s:%d", (OtherHost, PortNumber));
|
||||
}
|
||||
if (!FTerminal->SessionData->WebDavCrossDomainRedirects)
|
||||
{
|
||||
throw Exception(FMTLOAD(WEBDAV_CROSS_DOMAIN_REDIR, (OtherHost)));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -423,6 +423,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
|
||||
|
||||
// webdav page
|
||||
WebDavLiberalEscapingCheck->Checked = FSessionData->WebDavLiberalEscaping;
|
||||
WebDavCrossDomainRedirectsCheck->Checked = FSessionData->WebDavCrossDomainRedirects;
|
||||
|
||||
// color
|
||||
FColor = static_cast<TColor>(FSessionData->Color);
|
||||
@@ -716,6 +717,7 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
|
||||
|
||||
// webdav page
|
||||
SessionData->WebDavLiberalEscaping = WebDavLiberalEscapingCheck->Checked;
|
||||
SessionData->WebDavCrossDomainRedirects = WebDavCrossDomainRedirectsCheck->Checked;
|
||||
|
||||
// color
|
||||
SessionData->Color = FColor;
|
||||
|
||||
@@ -1190,13 +1190,13 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
Left = 8
|
||||
Top = 2
|
||||
Width = 438
|
||||
Height = 49
|
||||
Height = 72
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Protocol options'
|
||||
TabOrder = 0
|
||||
DesignSize = (
|
||||
438
|
||||
49)
|
||||
72)
|
||||
object WebDavLiberalEscapingCheck: TCheckBox
|
||||
Left = 11
|
||||
Top = 22
|
||||
@@ -1207,6 +1207,16 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
TabOrder = 0
|
||||
OnClick = DataChange
|
||||
end
|
||||
object WebDavCrossDomainRedirectsCheck: TCheckBox
|
||||
Left = 11
|
||||
Top = 45
|
||||
Width = 418
|
||||
Height = 17
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = '&Allow redirects to other hosts'
|
||||
TabOrder = 1
|
||||
OnClick = DataChange
|
||||
end
|
||||
end
|
||||
end
|
||||
object ConnSheet: TTabSheet
|
||||
|
||||
@@ -286,6 +286,7 @@ __published:
|
||||
TLabel *S3RoleArnLabel;
|
||||
TEdit *S3RoleArnEdit;
|
||||
TPanel *NavigationPanel;
|
||||
TCheckBox *WebDavCrossDomainRedirectsCheck;
|
||||
void __fastcall DataChange(TObject *Sender);
|
||||
void __fastcall FormShow(TObject *Sender);
|
||||
void __fastcall PageControlChange(TObject *Sender);
|
||||
|
||||
@@ -295,6 +295,7 @@
|
||||
#define OPENSSL_INIT_ERROR 784
|
||||
#define NO_PRIVATE_KEY 785
|
||||
#define ANCESTOR_TARGET_ERROR 786
|
||||
#define WEBDAV_CROSS_DOMAIN_REDIR 787
|
||||
|
||||
#define CORE_CONFIRMATION_STRINGS 300
|
||||
#define CONFIRM_PROLONG_TIMEOUT3 301
|
||||
|
||||
@@ -271,6 +271,7 @@ BEGIN
|
||||
OPENSSL_INIT_ERROR, "OpenSSL initialization failed"
|
||||
NO_PRIVATE_KEY, "No private key found in %s file."
|
||||
ANCESTOR_TARGET_ERROR, "Target of copy or move cannot be an ancestor directory of source."
|
||||
WEBDAV_CROSS_DOMAIN_REDIR, "Redirect to other host encountered. If you trust the target host %s, please allow redirects to other hosts in session settings."
|
||||
|
||||
CORE_CONFIRMATION_STRINGS, "CORE_CONFIRMATION"
|
||||
CONFIRM_PROLONG_TIMEOUT3, "Host is not communicating for %d seconds.\n\nWait for another %0:d seconds?"
|
||||
|
||||
Reference in New Issue
Block a user